Мне кажется, что файлы работают без этой строки.
Если у вас установлено несколько версий Python, /usr/bin/env
гарантирует, что используемый интерпретатор является первым в вашей среде $PATH
. Альтернативой могло бы быть hardcode что-то вроде #!/usr/bin/python
; это нормально, но менее гибко.
В Unix исполняемый файл, который должен интерпретироваться, может указывать, какой интерпретатор должен использовать, имея #!
в начале первой строки, за которым следует интерпретатор (и любые флаги, которые могут понадобиться).
Если вы говорите о других платформах, конечно, это правило не применяется (но эта строка "shebang" не наносит вреда и поможет, если вы когда-нибудь скопируете этот script на платформу с базой Unix, таких как Linux, Mac и т.д.).
chmod +x myscript.py
), а затем запускаете его напрямую: ./myscript.py
, а не просто python myscript.py
.
env
дает максимальную гибкость в том, что пользователь может выбрать интерпретатор для использования, изменив PATH. Часто эта гибкость не требуется, хотя и недостатком является то, что Linux, например, не может использовать имя сценария для имени процесса в ps
и возвращается к «python». Например, при упаковке приложений Python для дистрибутивов я бы не советовал использовать env
.
Это называется строка shebang. Поскольку запись Wikipedia объясняет:
В вычислениях shebang (также называемый hashbang, hashpling, pound bang или crunchbang) относится к символам "#!" когда они являются первыми двумя символами в директиве интерпретатора в качестве первой строки текстового файла. В Unix-подобной операционной системе загрузчик программ принимает эти два символа в качестве признака того, что файл является script, и пытается выполнить этот script с помощью интерпретатора, указанного в остальной части первой строки в файл.
См. также Запись в Unix FAQ.
Даже в Windows, где строка shebang не определяет интерпретатор, который должен быть запущен, вы можете передать параметры интерпретатору, указав их на линии shebang. Я считаю полезным хранить общую строку shebang в одноразовых сценариях (например, те, которые я пишу, когда отвечаю на вопросы о SO), поэтому я могу быстро протестировать их как на Windows, так и на ArchLinux.
утилита env позволяет вам вызывать команду на пути:
Первый оставшийся аргумент указывает имя программы для вызова; он выполняется в соответствии с переменной среды
PATH
. Любые оставшиеся аргументы передаются в качестве аргументов этой программы.
Развернувшись немного на других ответах, вот небольшой пример того, как ваши сценарии командной строки могут попасть в проблему путем неосторожного использования строк /usr/bin/env
shebang:
$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py
Traceback (most recent call last):
File "./my_script.py", line 2, in <module>
import json
ImportError: No module named json
Модуль json не существует в Python 2.5.
Один из способов защитить эту проблему - использовать имена команд с версией python, которые обычно устанавливаются с большинством Pythons:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Если вам просто нужно различать Python 2.x и Python 3.x, последние выпуски Python 3 также предоставляют имя python3
:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
возвращает /usr/bin/python
, путь к локальному каталогу может быть жестко задан: #!/usr/bin/python
. Но это менее гибко, чем #!/usr/bin/env python
который имеет глобальное приложение.
Чтобы запустить python script, нам нужно сказать оболочке три вещи:
Шебанг #!
выполняет (1.). Шебанг начинается с #
, потому что символ #
является маркером комментариев на многих языках сценариев. Поэтому содержимое строки shebang автоматически игнорируется интерпретатором.
Команда env
выполняет (2.) и (3.). Чтобы процитировать "грамотность",
Общепринятое использование команды
env
- запуск интерпретаторов путем создания использование того, что env будет искать $PATH для команды, о которой сказано запускать. Поскольку для линии shebang требуется абсолютный путь и поскольку местоположение различных переводчиков (perl, bash, python) может сильно различаться, обычно используется:
#!/usr/bin/env perl
вместо того, чтобы угадать, /bin/perl,/usr/bin/perl,/usr/local/bin/perl,/usr/local/pkg/perl, /fileserver/usr/bin/perl, или /home/MrDaniel/usr/bin/perl в пользовательской система...С другой стороны, env почти всегда находится в /usr/bin/env. (За исключением случаев, когда это не так; некоторые системы могут использовать /bin/env, но довольно редкое явление и происходит только в системах, отличных от Linux.)
Технически, в Python это просто строка комментариев.
Эта строка используется, только если вы запустите py script из оболочки (из командной строки). Это известно как "Shebang!" и используется в различных ситуациях, а не только с помощью скриптов Python.
Здесь он инструктирует оболочку запускать определенную версию Python (чтобы позаботиться о остальной части файла.
Возможно, ваш вопрос в этом смысле:
Если вы хотите использовать: $python myscript.py
Вам не нужна эта строка вообще. Система вызовет python, а затем интерпретатор python запустит ваш script.
Но если вы намерены использовать: $./myscript.py
Вызывая его напрямую, как обычная программа, или bash script, вам нужно написать эту строку, чтобы указать системе, для которой программа используется для ее запуска (а также сделать ее исполняемой с помощью chmod 755
)
Основная причина заключается в том, чтобы сделать перенос script переносимым по средам операционной системы.
Например, в mingw скрипты python используют:
#!/c/python3k/python
а в дистрибутиве GNU/Linux это либо:
#!/usr/local/bin/python
или
#!/usr/bin/python
и под лучшей коммерческой Unix sw/hw системой всех (OS/X), это:
#!/Applications/MacPython 2.5/python
или на FreeBSD:
#!/usr/local/bin/python
Однако все эти различия могут сделать перенос script переносимым на всех, используя:
#!/usr/bin/env python
/usr/bin/python
. Под Linux Python, установленный системой, также почти наверняка является /usr/bin/python
(я больше ничего не видел, и это не имело бы никакого смысла). Обратите внимание, что могут быть системы, которые не имеют /usr/bin/env
.
Системный вызов exec
в ядре Linux понимает shebangs (#!
) Изначально
Когда вы делаете бит:
./something
в Linux это вызывает системный вызов exec
с помощью пути ./something
.
Эта строка ядра вызывается в файле, переданном exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm-> buf [0]! = '#') || (bprm-> buf [1]! = '!'))
Это считывает первые байты файла и сравнивает их с #!
,
Если это так, то остальная часть строки анализируется ядром Linux, что делает другим вызовом exec с помощью пути /usr/bin/env python
и текущего файла в качестве первого аргумента:
/usr/bin/env python /path/to/script.py
и это работает для любого языка сценариев, который использует #
как символ комментария.
И да, вы можете сделать бесконечный цикл с:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash распознает ошибку:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
просто случается, что он читается человеком, но это не требуется.
Если файл начинался с разных байтов, тогда системный вызов exec
использовал бы другой обработчик. Другой самый важный встроенный обработчик - для исполняемых файлов ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, который проверяет байты 7f 45 4c 46
(что также оказывается, для человека удобочитаемым для .ELF
). Это считывает файл ELF, правильно помещает его в память и запускает с ним новый процесс. См. Также: Как ядро получает исполняемый двоичный файл, работающий под Linux?
Наконец, вы можете добавить своих собственных обработчиков shebang с binfmt_misc
механизма binfmt_misc
. Например, вы можете добавить настраиваемый обработчик для .jar
файлов. Этот механизм даже поддерживает обработчики с расширением файла. Другое приложение - прозрачно запускать исполняемые файлы другой архитектуры с помощью QEMU.
Я не думаю, что POSIX указывает shebangs: https://unix.stackexchange.com/a/346214/32558, хотя он упоминает в разделах объяснения и в форме "если исполняемые скрипты поддерживаются системой, что-то может случиться".
Возможно, имеет смысл подчеркнуть одну вещь, которую большинство пропустили, что может помешать немедленному пониманию. Когда вы вводите python
в терминале, вы обычно не предоставляете полный путь. Вместо этого исполняемый файл просматривается в переменной среды PATH
. В свою очередь, если вы хотите напрямую выполнить программу Python, /path/to/app.py
, нужно сказать оболочке, какой интерпретатор использовать (через хэш-бэнг, что другие участники объясняют выше).
Hashbang ожидает полный путь к интерпретатору. Таким образом, чтобы запустить вашу программу Python напрямую, вам необходимо предоставить полный путь к двоичному файлу Python, который значительно отличается, особенно с учетом использования virtualenv. Для решения проблемы переносимости используется трюк с /usr/bin/env
. Последнее изначально предназначено для изменения среды на месте и выполнения команды в ней. Когда никаких изменений не предусмотрено, она запускает команду в текущей среде, что эффективно приводит к тому же поиску PATH
, который делает трюк.
Рекомендуемый способ, предложенный в документации:
2.2.2. Исполняемые скрипты Python
В системах BSDish Unix скрипты Python могут быть сделаны напрямую исполняемый файл, подобно сценариям оболочки, путем размещения строки
#! /usr/bin/env python3.2
из http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Это соглашение оболочки, которое сообщает оболочке, какая программа может выполнить script.
#!/usr/bin/env python
разрешает путь к двоичному файлу Python.
Вы можете попробовать эту проблему, используя virtualenv
Вот test.py
#! /usr/bin/env python
import sys
print(sys.version)
Создание виртуальных сред
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
активируйте каждую среду, затем проверьте различия
echo $PATH
./test.py
Мне кажется, что файлы работают без этой строки.
Если да, то, возможно, вы запускаете программу Python в Windows? Windows не использует эту строку - вместо этого используется расширение имени файла для запуска программы, связанной с расширением файла.
Однако в 2011 году была разработана "Python launcher" , которая (в некоторой степени) имитирует этот Linux поведение для Windows. Это ограничивается только выбором того, какой интерпретатор Python запускается - например. для выбора между Python 2 и Python 3 в системе, где оба установлены. Пусковая установка может быть установлена как py.exe
с помощью установки Python и может быть связана с файлами .py
, чтобы запускающая программа проверила эту строку и, в свою очередь, запустила указанную версию интерпретатора Python.
$ python myscript.py
.
Это подразумевается как большая часть исторической информации, чем "реальный" ответ.
Помните, что в тот же день, когда у вас были LOTS unix, такие как операционные системы, разработчики которых имели собственное представление о том, куда помещать материал, а иногда не включали Python, Perl, Bash или множество других GNU/С открытым исходным кодом вообще.
Это справедливо и для разных дистрибутивов Linux. В Linux - pre-FHS [1] - у вас может быть python в/usr/bin/или/usr/local/bin/. Или он, возможно, не был установлен, поэтому вы создали свой собственный и поместили его в ~/bin
Solaris была худшим, над чем я когда-либо работал, частично как переход от Berkeley Unix к System V. Вы можете завершить работу в/usr/,/usr/local/,/usr/ucb,/opt/и т.д. Это может привести к некоторым действительно длинным путям. У меня есть воспоминания о материалах из Sunfreeware.com, устанавливающих каждый пакет в его собственный каталог, но я не могу вспомнить, привязывал ли они бинарные файлы в /usr/bin или нет.
О, а иногда /usr/bin был на сервере NFS [2].
Итак, утилита env
была разработана, чтобы обойти это.
Тогда вы могли бы написать #!/bin/env interpreter
и до тех пор, пока путь был правильным, у него были разумные шансы на запуск. Разумеется, разумный смысл (для Python и Perl) заключается в том, что вы также установили соответствующие переменные среды. Для bash/ksh/zsh это просто сработало.
Это было важно, потому что люди проходили вокруг сценариев оболочки (например, perl и python), и если бы вы жестко закодировали /usr/bin/python на своей рабочей станции Red Hat Linux, это сильно испортило бы SGI... ну, нет, я думаю, что IRIX поставил python в нужное место. Но на станции Sparc это может не сработать.
Я скучаю по моей спарковой станции. Но не много. Хорошо, теперь у тебя есть троллинг в E-Bay. Bastages.
[1] Стандарт иерархии файловой системы. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Да, и иногда люди все еще делают такие вещи. И нет, я не носил репы или лука на поясе.
Он просто указывает, какой интерпретатор вы хотите использовать. Чтобы понять это, создайте файл через терминал, выполнив touch test.py
, затем введите в этот файл следующее:
#!/usr/bin/env python3
print "test"
и выполните chmod +x test.py
, чтобы выполнить ваш script исполняемый файл. После этого, когда вы делаете ./test.py
, вы должны получить сообщение об ошибке:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
потому что python3 не поддерживает оператор печати.
Теперь перейдите и измените первую строку своего кода на:
#!/usr/bin/env python2
и он будет работать, печатая test
в stdout, потому что python2 поддерживает оператор печати. Итак, теперь вы узнали, как переключаться между script интерпретаторами.
Если вы используете script в виртуальной среде, скажем venv
, тогда выполнение which python
при работе над venv
будет отображать путь к интерпретатору Python:
~/Envs/venv/bin/python
Обратите внимание, что имя виртуальной среды встроено в путь к интерпретатору Python. Следовательно, hardcoding этот путь в вашем script вызовет две проблемы:
Поэтому, чтобы добавить к Jonathan ответ, идеальный shebang #!/usr/bin/env python
, а не только для переносимости между ОС, но для переносимость в виртуальных средах!
Учитывая проблемы переносимости между python2
и python3
, вы всегда должны указывать любую версию, если ваша программа не совместима с обоими.
Некоторые дистрибутивы в течение некоторого времени отправляют python
с символикой python3
- не полагайтесь на python
на python2
.
Это подчеркивается PEP 394:
Чтобы переносить различия между платформами, весь новый код, который необходимо вызвать интерпретатор Python, не следует указывать python, но скорее следует указать либо python2, либо python3 (или более конкретный python2.x и python3.x; см. Заметки о переносе). Эта различие должно быть сделано в shebangs, при вызове из оболочки script, при вызове через вызов system() или при вызове в любом в другом контексте.
Он сообщает интерпретатору, какая версия python запускает программу, когда у вас есть несколько версий python.
это сообщает script, где находится каталог python!
#! /usr/bin/env python
#!/usr/bin/env python
вверху.