Работа с шебенг (#!)
Nov 3, 2014 20:21 · 527 words · 3 minute read
Уже второй раз за выходные натыкаюсь на особенность моей ОС - работа с шебенг. Это понятие применительно исключительно к миру *nix. Если вкратце, то это первая строка в файле, которая говорит с помощью какой программы оный запускать. Наверняка сталкивались с нечто похожим: #!/bin/bash или #!/usr/bin/python- это оно и есть :) Вернее, не совсем так, должны быть соблюдены следующие условия:
- файл исполняемый (**x);
- файл не бинарный (в противном случае он запустится “как exe-шник”);
- первые 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 не запускается, то скорее всего дело в первой магической строчке.