Как / usr / bin / env знает, какую программу использовать?

62

Когда я использую шебанг #!/usr/bin/env pythonдля запуска скрипта, как система узнает, какой pythonиспользовать? если я ищу pythonпуть бин в переменных среды, я ничего не нахожу.

env | grep -i python
TMC
источник
6
о, я думаю, я понял это - он просто ищет ваш $ PATH на «python»
tMC
Я тоже об этом думал. И почему / usr / bin / env? в отличие от / bin / env или env, если он просто получает список путей из env?
Фахим Митха
Просто env не сработает, потому что это должен быть полный путь. Программа 'env' обычно находится в / user / bin / env. В некоторых дистрибутивах его также можно найти как / bin / env, но безопаснее использовать / usr / bin / env.
Реттопс

Ответы:

55

Шебанг ожидает, что будет использован полный путь к интерпретатору, поэтому следующий синтаксис будет неправильным:

#!python

Установка полного пути, как это может работать:

#!/usr/local/bin/python

но было бы не портативная , как питон может быть установлен /bin, /opt/python/binили где -то другое место.

С помощью env

#!/usr/bin/env python

это метод, позволяющий переносимым способом указать ОС полный путь, эквивалентный тому, где pythonон впервые находится в PATH.

jlliagre
источник
57

Линия Шебанга (от «резкого взрыва», т.е. #!) обрабатывается ядром. Ядро не хочет знать о переменных среды, таких как PATH. Таким образом, имя в строке shebang должно быть абсолютным путем к исполняемому файлу. Вы также можете указать дополнительный аргумент для передачи в этот исполняемый файл перед именем скрипта (с системно-зависимыми ограничениями я не буду здесь вдаваться). Например, для скрипта Python вы можете указать

#!/usr/bin/python

в первой строке, и когда вы выполняете скрипт, ядро ​​будет фактически выполнено /usr/bin/python /path/to/script. Но это не удобно: вам нужно указать полный путь к команде. Что делать , если у вас есть pythonв /usr/binна некоторых машинах и /usr/local/binна других? Или вы хотите установить PATHдля /home/joe/opt/python-2.5/binтого, чтобы использовать конкретную версию Python? Поскольку ядро ​​не будет выполнять PATHпоиск за вас, идея состоит в том, чтобы заставить ядро ​​запустить команду, которая, в свою очередь, ищет нужный интерпретатор в PATH:

#!/fixed/path/to/path-lookup-command python

Это path-lookup-commandдолжно взять имя исполняемого файла в качестве аргумента, найти его PATHи выполнить: ядро ​​запустится /fixed/path/to/path-lookup-command python /path/to/script. Как это бывает, envкоманда делает именно это. Его основная цель - запустить команду в другой среде, но, поскольку она ищет имя команды $PATH, она идеально подходит для нашей цели.

Хотя это официально не гарантировано, исторические системы Unix при условии , envв /usr/bin, и современные системы сохранили это место именно из-за широкого использования #!/usr/bin/env. Таким образом, на практике способ указать, что скрипт должен выполняться любимым интерпретатором Python пользователя,

#!/usr/bin/env python
Жиль "ТАК - перестань быть злым"
источник
2
какой из них предпочтительнее между envи which? поскольку он также получит наиболее подходящий исполняемый файл из моей среды PATH.
Nikhil Mulley
8
@NikhilMulley whichнаходит исполняемый файл и печатает его путь. envнаходит программу, указанную в первом аргументе, и выполняет ее, передавая оставшиеся аргументы.
Кевин
3
так это то, что envэто eval версия по whichсуществу.
Nikhil Mulley
7

Хорошо, так что беги:

env | grep PATH

Ваш $ PATH - это список каталогов. Unix будет проходить этот список каталогов по порядку, пока не найдет «python».

Вы можете увидеть, какой каталог он находит с помощью команды which:

which python
Дан Рю
источник
Интересно, что я вижу разницу в python sys.pathмежду активированными env $ env python3 ( ['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']) и ./env/bin/python3 (['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/test/env3/lib/python3.4/site-packages']).
ThorSummoner