Почему люди пишут #! / Usr / bin / env pybang в первой строке скрипта Python?

883

Мне кажется, что файлы работают без этой строки.

  • 1
    Ответ ниже утверждает, что это просто строка комментария. Это не всегда так. У меня есть «Привет, мир!» CGI-скрипт (.py), который будет запускаться и отображать веб-страницу только с #!/usr/bin/env python вверху.
  • 1
    Возможный дубликат В чем разница между этими двумя питон шебанги
Показать ещё 2 комментария
Теги:
shebang

19 ответов

959

Если у вас установлено несколько версий Python, /usr/bin/env гарантирует, что используемый интерпретатор является первым в вашей среде $PATH. Альтернативой могло бы быть hardcode что-то вроде #!/usr/bin/python; это нормально, но менее гибко.

В Unix исполняемый файл, который должен интерпретироваться, может указывать, какой интерпретатор должен использовать, имея #! в начале первой строки, за которым следует интерпретатор (и любые флаги, которые могут понадобиться).

Если вы говорите о других платформах, конечно, это правило не применяется (но эта строка "shebang" не наносит вреда и поможет, если вы когда-нибудь скопируете этот script на платформу с базой Unix, таких как Linux, Mac и т.д.).

  • 232
    Просто добавить: это применимо, когда вы запускаете его в Unix, делая его исполняемым ( chmod +x myscript.py ), а затем запускаете его напрямую: ./myscript.py , а не просто python myscript.py .
  • 24
    Использование env дает максимальную гибкость в том, что пользователь может выбрать интерпретатор для использования, изменив PATH. Часто эта гибкость не требуется, хотя и недостатком является то, что Linux, например, не может использовать имя сценария для имени процесса в ps и возвращается к «python». Например, при упаковке приложений Python для дистрибутивов я бы не советовал использовать env .
Показать ещё 13 комментариев
225

Это называется строка shebang. Поскольку запись Wikipedia объясняет:

В вычислениях shebang (также называемый hashbang, hashpling, pound bang или crunchbang) относится к символам "#!" когда они являются первыми двумя символами в директиве интерпретатора в качестве первой строки текстового файла. В Unix-подобной операционной системе загрузчик программ принимает эти два символа в качестве признака того, что файл является script, и пытается выполнить этот script с помощью интерпретатора, указанного в остальной части первой строки в файл.

См. также Запись в Unix FAQ.

Даже в Windows, где строка shebang не определяет интерпретатор, который должен быть запущен, вы можете передать параметры интерпретатору, указав их на линии shebang. Я считаю полезным хранить общую строку shebang в одноразовых сценариях (например, те, которые я пишу, когда отвечаю на вопросы о SO), поэтому я могу быстро протестировать их как на Windows, так и на ArchLinux.

утилита env позволяет вам вызывать команду на пути:

Первый оставшийся аргумент указывает имя программы для вызова; он выполняется в соответствии с переменной среды PATH. Любые оставшиеся аргументы передаются в качестве аргументов этой программы.

  • 28
    Легко найти с помощью Google - если кто-то знает ключевые слова («линия Шебанга» имеет важное значение).
  • 10
    На самом деле, это объяснение яснее, чем другие ссылки, которые я проверял в Google. Всегда лучше получить 1 параграф объяснения, нацеленного на вопрос, а не читать полное руководство по каждому потенциальному использованию.
Показать ещё 2 комментария
144

Развернувшись немного на других ответах, вот небольшой пример того, как ваши сценарии командной строки могут попасть в проблему путем неосторожного использования строк /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")
  • 27
    Хм, это не то, что я получил от этого поста.
  • 0
    Разница между локальным и глобальным. Если which python возвращает /usr/bin/python , путь к локальному каталогу может быть жестко задан: #!/usr/bin/python . Но это менее гибко, чем #!/usr/bin/env python который имеет глобальное приложение.
76

Чтобы запустить python script, нам нужно сказать оболочке три вещи:

  • Что файл script
  • Какой интерпретатор мы хотим выполнить 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.)

  • 1
    "Гравитация" где?
39

Технически, в Python это просто строка комментариев.

Эта строка используется, только если вы запустите py script из оболочки (из командной строки). Это известно как "Shebang!" и используется в различных ситуациях, а не только с помощью скриптов Python.

Здесь он инструктирует оболочку запускать определенную версию Python (чтобы позаботиться о остальной части файла.

37

Возможно, ваш вопрос в этом смысле:

Если вы хотите использовать: $python myscript.py

Вам не нужна эта строка вообще. Система вызовет python, а затем интерпретатор python запустит ваш script.

Но если вы намерены использовать: $./myscript.py

Вызывая его напрямую, как обычная программа, или bash script, вам нужно написать эту строку, чтобы указать системе, для которой программа используется для ее запуска (а также сделать ее исполняемой с помощью chmod 755)

  • 0
    или вы можете написать python3 myscript.py
33

Основная причина заключается в том, чтобы сделать перенос 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
  • 1
    Под MacOSX это также /usr/bin/python . Под Linux Python, установленный системой, также почти наверняка является /usr/bin/python (я больше ничего не видел, и это не имело бы никакого смысла). Обратите внимание, что могут быть системы, которые не имеют /usr/bin/env .
  • 1
    Если вы используете OSX и используете Homebrew и следуете инструкциям по умолчанию, он будет находиться под #! / Usr / local / bin / python
Показать ещё 3 комментария
25

Системный вызов 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, хотя он упоминает в разделах объяснения и в форме "если исполняемые скрипты поддерживаются системой, что-то может случиться".

19

Возможно, имеет смысл подчеркнуть одну вещь, которую большинство пропустили, что может помешать немедленному пониманию. Когда вы вводите python в терминале, вы обычно не предоставляете полный путь. Вместо этого исполняемый файл просматривается в переменной среды PATH. В свою очередь, если вы хотите напрямую выполнить программу Python, /path/to/app.py, нужно сказать оболочке, какой интерпретатор использовать (через хэш-бэнг, что другие участники объясняют выше).

Hashbang ожидает полный путь к интерпретатору. Таким образом, чтобы запустить вашу программу Python напрямую, вам необходимо предоставить полный путь к двоичному файлу Python, который значительно отличается, особенно с учетом использования virtualenv. Для решения проблемы переносимости используется трюк с /usr/bin/env. Последнее изначально предназначено для изменения среды на месте и выполнения команды в ней. Когда никаких изменений не предусмотрено, она запускает команду в текущей среде, что эффективно приводит к тому же поиску PATH, который делает трюк.

Источник из unix stackexchange

12

Рекомендуемый способ, предложенный в документации:

2.2.2. Исполняемые скрипты Python

В системах BSDish Unix скрипты Python могут быть сделаны напрямую исполняемый файл, подобно сценариям оболочки, путем размещения строки

#! /usr/bin/env python3.2

из http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts

10

Это соглашение оболочки, которое сообщает оболочке, какая программа может выполнить script.

#!/usr/bin/env python

разрешает путь к двоичному файлу Python.

9

Вы можете попробовать эту проблему, используя 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
7

Мне кажется, что файлы работают без этой строки.

Если да, то, возможно, вы запускаете программу Python в Windows? Windows не использует эту строку - вместо этого используется расширение имени файла для запуска программы, связанной с расширением файла.

Однако в 2011 году была разработана "Python launcher" , которая (в некоторой степени) имитирует этот Linux поведение для Windows. Это ограничивается только выбором того, какой интерпретатор Python запускается - например. для выбора между Python 2 и Python 3 в системе, где оба установлены. Пусковая установка может быть установлена ​​как py.exe с помощью установки Python и может быть связана с файлами .py, чтобы запускающая программа проверила эту строку и, в свою очередь, запустила указанную версию интерпретатора Python.

  • 6
    Он также может использовать $ python myscript.py .
  • 0
    Я сделал ошибку, не имея строки, и использовал python script.py, и однажды я просто сделал ./myscript.py, и все перестало работать, а затем понял, что система ищет файл как сценарий оболочки вместо сценария python.
4

Это подразумевается как большая часть исторической информации, чем "реальный" ответ.

Помните, что в тот же день, когда у вас были 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] Да, и иногда люди все еще делают такие вещи. И нет, я не носил репы или лука на поясе.

4

Он просто указывает, какой интерпретатор вы хотите использовать. Чтобы понять это, создайте файл через терминал, выполнив 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 интерпретаторами.

4

Если вы используете script в виртуальной среде, скажем venv, тогда выполнение which python при работе над venv будет отображать путь к интерпретатору Python:

~/Envs/venv/bin/python

Обратите внимание, что имя виртуальной среды встроено в путь к интерпретатору Python. Следовательно, hardcoding этот путь в вашем script вызовет две проблемы:

  • Если вы загружаете script в репозиторий, вы заставляете других пользователей иметь одно и то же имя виртуальной среды. Это если они сначала идентифицируют проблему.
  • Вы не сможете запускать script в нескольких виртуальных средах, даже если у вас есть все необходимые пакеты в других виртуальных средах.

Поэтому, чтобы добавить к Jonathan ответ, идеальный shebang #!/usr/bin/env python, а не только для переносимости между ОС, но для переносимость в виртуальных средах!

3

Учитывая проблемы переносимости между python2 и python3, вы всегда должны указывать любую версию, если ваша программа не совместима с обоими.

Некоторые дистрибутивы в течение некоторого времени отправляют python с символикой python3 - не полагайтесь на python на python2.

Это подчеркивается PEP 394:

Чтобы переносить различия между платформами, весь новый код, который необходимо вызвать интерпретатор Python, не следует указывать python, но скорее следует указать либо python2, либо python3 (или более конкретный python2.x и python3.x; см. Заметки о переносе). Эта различие должно быть сделано в shebangs, при вызове из оболочки script, при вызове через вызов system() или при вызове в любом в другом контексте.

2

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

-7

это сообщает script, где находится каталог python!

#! /usr/bin/env python

Ещё вопросы

Сообщество Overcoder
Наверх
Меню