Мне кажется, что файлы без этой строки работают одинаково.
Мне кажется, что файлы без этой строки работают одинаково.
Ответы:
Если у вас установлено несколько версий Python, /usr/bin/env
убедитесь, что используемый интерпретатор является первым в вашей среде $PATH
. Альтернативой было бы жестко закодировать что-то вроде#!/usr/bin/python
; это нормально, но менее гибко.
В Unix исполняемый файл, предназначенный для интерпретации, может указывать, какой интерпретатор использовать, имея #!
в начале первой строки, за которым следует интерпретатор (и любые флаги, которые могут ему понадобиться).
Если вы говорите о других платформах, конечно, это правило не применяется (но эта «линия Шебанга» не причиняет вреда и поможет, если вы когда-нибудь скопируете этот скрипт на платформу с базой Unix, такую как Linux, Mac , так далее).
chmod +x myscript.py
), а затем запускаете его напрямую: ./myscript.py
вместо простого python myscript.py
.
env
дает максимальную гибкость в том, что пользователь может выбрать интерпретатор для использования путем изменения PATH. Часто эта гибкость не требуется, хотя и недостатком является то, что Linux, например, не может использовать имя сценария для имени процесса ps
и возвращается к «python». При упаковке приложений Python для дистрибутивов, например, я бы советовал не использовать env
.
py
Launcher может использовать строку Shebang на Windows. Он включен в Python 3.3 или может быть установлен независимо .
/usr/bin/env: Key has expired
через много часов.
Это называется линией Шебанга . Как объясняется запись в Википедии :
В вычислениях шебанг (также называемый хэш-бэнг, хэшплинг, фунт-бэнг или хруст-бэнг) относится к символам "#!" когда они являются первыми двумя символами в директиве интерпретатора в качестве первой строки текстового файла. В Unix-подобной операционной системе загрузчик программы воспринимает присутствие этих двух символов как указание на то, что файл является сценарием, и пытается выполнить этот сценарий, используя интерпретатор, указанный в оставшейся части первой строки файла.
Смотрите также запись FAQ по Unix .
Даже в Windows, где строка shebang не определяет интерпретатор для запуска, вы можете передать опции интерпретатору, указав их в строке shebang. Я считаю полезным хранить общую строку shebang в одноразовых скриптах (например, тех, которые я пишу, отвечая на вопросы по SO), чтобы я мог быстро протестировать их как в Windows, так и в ArchLinux .
Утилита окр позволяет выполнить команду на пути:
Первый оставшийся аргумент указывает имя программы для вызова; ищется по
PATH
переменной окружения. Все оставшиеся аргументы передаются в качестве аргументов этой программе.
Немного расширив остальные ответы, приведу небольшой пример того, как ваши скрипты командной строки могут попасть в неприятности из-за неосторожного использования /usr/bin/env
строк Шебанга:
$ /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, которые обычно устанавливаются с большинством питонов:
$ 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, нам нужно сказать оболочке три вещи:
Шебанг #!
выполняет (1.). Шебанг начинается с символа, #
потому что #
символ является маркером комментария во многих языках сценариев. Поэтому содержимое строки Шебанга автоматически игнорируется интерпретатором.
Команда 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 myscript.py
Вам не нужна эта линия вообще. Система вызовет python, а затем интерпретатор python запустит ваш скрипт.
Но если вы собираетесь использовать: $./myscript.py
Вызывая его напрямую, как обычную программу или скрипт bash, вам нужно написать эту строку, чтобы указать системе, какую программу использовать для ее запуска, (а также сделать ее исполняемой с chmod 755
)
exec
Системный вызов в Linux ядро понимает shebangs ( #!
) изначально
Когда вы делаете на Bash:
./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
). Давайте подтвердим это, прочитав 4 первых байта /bin/ls
, который является исполняемым файлом ELF:
head -c 4 "$(which ls)" | hd
вывод:
00000000 7f 45 4c 46 |.ELF|
00000004
Поэтому, когда ядро видит эти байты, оно берет файл ELF, правильно помещает его в память и запускает новый процесс с ним. Смотрите также: Как ядро получает исполняемый двоичный файл, работающий под Linux?
Наконец, вы можете добавить свои собственные обработчики shebang с binfmt_misc
механизмом. Например, вы можете добавить пользовательский обработчик для .jar
файлов . Этот механизм даже поддерживает обработчики по расширению файла. Другое приложение - для прозрачного запуска исполняемых файлов другой архитектуры с QEMU .
Я не думаю, что POSIX определяет shebangs, однако: https://unix.stackexchange.com/a/346214/32558 , хотя он упоминается в разделах обоснования и в форме «если исполняемые сценарии поддерживаются системой, что-то может случиться». macOS и FreeBSD также, похоже, реализуют это.
PATH
поисковая мотивация
Вероятно, одной большой мотивацией для существования шебангов является тот факт, что в Linux мы часто хотим запускать команды так PATH
же, как:
basename-of-command
вместо:
/full/path/to/basename-of-command
Но тогда, без механизма shebang, как Linux узнает, как запускать файлы каждого типа?
Жесткое кодирование расширения в командах:
basename-of-command.py
или осуществляя поиск PATH на каждом интерпретаторе:
python basename-of-command
было бы возможно, но это главная проблема, что все ломается, если мы когда-нибудь решим реорганизовать команду на другой язык.
Шебангс прекрасно решает эту проблему.
Технически, в Python это просто строка комментария.
Эта строка используется только если вы запускаете скрипт py из оболочки (из командной строки). Это известно как " Шебанг !" и используется в различных ситуациях, а не только в сценариях Python.
Здесь он указывает оболочке запустить определенную версию Python (чтобы позаботиться об остальной части файла.
py.exe
. Это часть стандартной установки Python.
Основная причина сделать это - сделать скрипт переносимым между средами операционной системы.
Например, в 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
Однако все эти различия могут сделать сценарий переносимым через все:
#!/usr/bin/env python
/usr/bin/python
. Под Linux Python, установленный системой, также почти наверняка /usr/bin/python
(я больше ничего не видел, и это не имело бы никакого смысла). Обратите внимание, что могут быть системы, которые не имеют /usr/bin/env
.
python
не так переносим, это дистрибутив Python по умолчанию. Arch Linux по умолчанию установлен на Python 3 долгое время, и, возможно, дистрибутивы тоже думают об этом, потому что Python 2 поддерживается только до 2020 года.
Вероятно, имеет смысл подчеркнуть одну вещь, которую большинство пропустило, что может помешать немедленному пониманию. Когда вы печатаете python
в терминале, вы обычно не указываете полный путь. Вместо этого исполняемый файл ищется в PATH
переменной окружения. В свою очередь, когда вы хотите выполнить программу на Python напрямую, /path/to/app.py
нужно указать оболочке, какой интерпретатор использовать (через hashbang , что другие авторы объясняют выше).
Hashbang ожидает полного пути к переводчику. Таким образом, чтобы запустить вашу программу на Python напрямую, вы должны указать полный путь к двоичному файлу Python, который значительно варьируется, особенно с учетом использования virtualenv . Для решения переносимости используется трюк с /usr/bin/env
. Последний изначально предназначен для изменения среды на месте и запуска в ней команды. Если никаких изменений не предусмотрено, команда запускается в текущей среде, что фактически приводит к тому жеPATH
поиску, что и уловка.
Это соглашение оболочки, которое сообщает оболочке, какая программа может выполнить скрипт.
#! / usr / bin / env python
разрешает путь к двоичному файлу Python.
Рекомендуемый способ, предложенный в документации:
2.2.2. Исполняемые скрипты Python
В системах BSD Unish, скрипты Python можно сделать непосредственно исполняемыми, например скрипты оболочки, поставив строку
#! /usr/bin/env python3.2
от http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Вы можете попробовать эту проблему, используя 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
Он просто указывает, какой интерпретатор вы хотите использовать. Чтобы понять это, создайте файл через терминал, выполнив touch test.py
, затем введите в этот файл следующее:
#!/usr/bin/env python3
print "test"
и сделать, chmod +x test.py
чтобы сделать ваш скрипт исполняемым. После этого, когда вы делаете, ./test.py
вы должны получить сообщение об ошибке:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
потому что python3 не поддерживает оператор печати.
Теперь перейдите и измените первую строку вашего кода на:
#!/usr/bin/env python2
и он будет работать, печатая test
на стандартный вывод, потому что python2 поддерживает оператор печати. Итак, теперь вы узнали, как переключаться между интерпретаторами сценариев.
Мне кажется, что файлы без этой строки работают одинаково.
Если так, то, возможно, вы используете программу Python в Windows? Windows не использует эту строку - вместо этого она использует расширение имени файла для запуска программы, связанной с расширением файла.
Однако в 2011 году был разработан «модуль запуска Python», который (в некоторой степени) имитирует такое поведение Linux для Windows. Это ограничивается только выбором запускаемого интерпретатора Python - например, для выбора между Python 2 и Python 3 в системе, где установлены оба. Модуль запуска по выбору устанавливается как py.exe
при установке Python и может быть связан с .py
файлами, так что модуль запуска проверяет эту строку и, в свою очередь, запускает указанную версию интерпретатора Python.
$ python myscript.py
.
Это означает больше исторической информации, чем «реального» ответа.
Помните , что еще в день вы имели МНОГО UNIX - подобные операционные системам , в которых дизайнеры все имел свое собственное представление о том, где положить вещи, а иногда и не включает в себя Python, Perl, Bash, или много другого GNU / Open Source материала на все ,
Это было даже верно для разных дистрибутивов 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 он может вообще не работать.
Я скучаю по своей станции sparc. Но не много. Хорошо, теперь ты заставляешь меня троллить по E-Bay. Bastages.
[1] Стандарт иерархии файловой системы. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Да, и иногда люди все еще делают подобные вещи. И нет, я не носил на поясе ни репы, ни лука.
Например, если вы выполняете свой сценарий в виртуальной среде, venv
то выполнение which python
во время работы venv
покажет путь к интерпретатору Python:
~/Envs/venv/bin/python
Обратите внимание, что имя виртуальной среды встроено в путь к интерпретатору Python. Поэтому жесткое кодирование этого пути в вашем скрипте вызовет две проблемы:
Поэтому, чтобы добавить к ответу Джонатана , идеальный шебанг#!/usr/bin/env python
не только переносимость между операционными системами, но и переносимость между виртуальными средами!
Учитывая проблемы переносимости между python2
иpython3
, вы всегда должны указывать любую версию, если ваша программа не совместима с обеими.
Некоторые дистрибутивы поставляются python
слинкованы в python3
то время как сейчас - не полагаться на python
существеpython2
.
Это подчеркивается ПКП 394 :
Чтобы допустить различия между платформами, весь новый код, который должен вызывать интерпретатор Python, не должен указывать python, а должен указывать либо python2, либо python3 (или более конкретные версии python2.x и python3.x; см. Примечания по миграции ). , Это различие следует делать в шебангах, при вызове из сценария оболочки, при вызове через вызов system () или при вызове в любом другом контексте.
Это позволяет вам выбрать исполняемый файл, который вы хотите использовать; что очень удобно, если, возможно, у вас есть несколько установок Python и разные модули в каждом и вы хотите выбрать. например
#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3
if [ -x $PREFERRED_PYTHON ]; then
echo Using preferred python $ALTERNATIVE_PYTHON
exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
echo Using alternative python $ALTERNATIVE_PYTHON
exec $ALTERNATIVE_PYTHON "$0" "$@"
else
echo Using fallback python $FALLBACK_PYTHON
exec python3 "$0" "$@"
fi
exit 127
'''
__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())
Строка #!/bin/bash/python3
или #!/bin/bash/python
указывает, какой компилятор Python использовать. У вас может быть установлено несколько версий Python. Например,
a.py:
#!/bin/bash/python3
print("Hello World")
это скрипт на python3, а
b.py:
#!/bin/bash/python
print "Hello World"
является скриптом Python 2.x
Чтобы запустить ./a.py
или ./b.py
использовать этот файл , вам необходимо дать привилегии выполнения файлов заранее, иначе выполнение приведет к Permission denied
ошибке.
Для предоставления разрешения на исполнение,
chmod +x a.py
это говорит сценарию, где находится каталог python!
#! /usr/bin/env python
#!/usr/bin/env python
только вверху.