Работа с шебенг (#!)

Nov 3, 2014 20:21 · 527 words · 3 minute read админство python

Уже второй раз за выходные натыкаюсь на особенность моей ОС - работа с шебенг. Это понятие применительно исключительно к миру *nix. Если вкратце, то это первая строка в файле, которая говорит с помощью какой программы оный запускать. Наверняка сталкивались с нечто похожим: #!/bin/bash или #!/usr/bin/python- это оно и есть :) Вернее, не совсем так, должны быть соблюдены следующие условия:

  1. файл исполняемый (**x);
  2. файл не бинарный (в противном случае он запустится “как exe-шник”);
  3. первые 2 байта должны быть # и !, после них идёт строка с именем выполняемой программы.

На первый взгляд ничего сложного, но на граблях я буквально танцевал. Под катом 2 таких случая.

Виртуальное окружение

Передали мне небольшой проект на Django - десяток моделей в одном приложении, ну ладно, бывает, не обратил особого внимания. Надо бы локально развернуть… Запасся попкорном, включил фильм на втором мониторе, приглушил мозговую активность и взялся за дело. Таблицы в postgres залил, виртуальное окружение создал, настроил uwsgi и nginx, осталось сам проект запустить:

tyvik@Server ~/Projects/django/project $ workon djangoenv
(djangoenv)tyvik@Server ~/Projects/django/project $ vim manage.py 
(djangoenv)tyvik@Server ~/Projects/django/project $ ./manage.py runserver
Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    from django.core.management import execute_manager
ImportError: No module named django.core.management

Стоп! Как это нет!? Я аж фильм на паузу поставил… Точно помню, что ставил именно в виртуальное окружение Django 1.3.1, пробую:

(djangoenv)tyvik@Server ~/Projects/django/project $ django-admin.py --version
1.3.1

Что-то здесь не чисто… Ладно, исходники нам всё расскажут, смотрю manage.py (немного изменил для читаемости):

#!/usr/bin/python
import sys

from django.core.management import execute_manager
try:
    import settings # Assumed to be in the same directory.
except ImportError:
    sys.exit(1)

if __name__ == "__main__":
    execute_manager(settings)

Вот что здесь может быть не так?! По трейсу исключение python уже в третьей строке, и тут я натыкаюсь на замечательный шебенг, который говорит: “Мне до лампочки твоё виртуальное окружение, запускай системный python, который лежит в /usr/bin/python”. В системном питоне у меня конечно же никакого Django нет. так что интерпретатор полностью прав. Хорошо, а как же тогда вызвать его копию из виртуального окружения? Всё просто замечательно и решилось одной строкой: вместо #!/usr/bin/python следует писать #!/usr/bin/env python. Поэтому, пожалуйста, пишите в шебенге команду для запуска исходя из того, что она будет выполняться в виртуальном окружении.

Не все шебенги одинаково полезны

Решил я посмотреть на coffee-script, а для начала установить его компилятор в js. Такой есть, разумеется, только под nodejs, хоть я и не его поклонник, но, видимо, придётся ставить. С другой стороны это просто рабочий инструмент. То, что он написан на javascript для движка браузера здесь меня абсолютно не должно волновать.

tyvik@Server ~ $ sudo apt-get install nodejs npm
tyvik@Server ~ $ sudo npm install -g coffee-script
tyvik@Server ~ $ coffee -v
tyvik@Server ~ $

А где вывод версии??? Смотрим сам скрипт, который лежит в /usr/local/bin. Первая строчка: #!/usr/bin/env node. Ok, я уже научен горьким опытом, пробую запустить отдельно node - тишина, придётся гуглить. Решение нашлось довольно быстро - оказывается, под Ubuntu младше 16.04 имя node уже занято, а интерпретатор вызывается через команду nodejs. Меняем node на nodejs и всё сразу становится рабочим :) К сожалению, я не нашёл способа как это культурно починить (обошёлся созданием симлинка с node на nodejs), так что если программа на nodejs не запускается, то скорее всего дело в первой магической строчке.