Почему Python в Linux требует строки #! / Usr / bin / python?


50

Довольно простой вопрос: в Linux, почему Python требует строки

#!/usr/bin/python

в начале файла Python, так как Windows нет?

Что оно делает? потому что описание "Ссылки на Python" немного расплывчато ...


29
Все ответы ниже верны, ни один из них не объясняет, почему Windows не нужна эта строка. Windows зависит от расширения файла (часть после .), чтобы определить, какой это тип файла. Даже Windows отходит от этого: изучите первые несколько строк файла Microsoft Word, и он скажет, что на самом деле это файл Microsoft Word.
Чарльз Грин

10
Слон в комнате заключается в том, что вы НИКОГДА не должны использовать / usr / bin / python, если вы не совместимы с python 2 и 3. Причина: arch символизирует его с python3, ход, который признан PSF, который рекомендует против себя.
Еще один пользователь

7
Это подразумевается, но не указано явно в ответах ниже, что это не требуется . Это необходимо, если вы хотите выполнить скрипт только от своего имени. Вы всегда можете запустить python myscript.pyвместо этого.
Крис Х

3
@CharlesGreen мы не должны знать, почему Windows не делает ;-) Это до ТА.
Rinzwind

2
@YetAnotherUser Прошло шесть лет и одиннадцать месяцев с тех пор, как был выпущен Python 3, и сейчас я чувствую, что людям лучше по умолчанию использовать 3 и явно указывать использование 2 в случае необходимости.
JAB

Ответы:


59

У Python нет таких особых требований к Linux. Это загрузчик программ в Unix / Linux, который использует строку «shebang», как она называется. На самом деле это скорее функция, чем ограничение, но мы вернемся к этому чуть позже. На вики-странице "shebang" есть больше деталей, но я постараюсь дать обзор, а также сравнение с Windows здесь.

Сначала давайте посмотрим на ситуацию в Windows:

  • Когда вы пытаетесь открыть или запустить файл, Windows сначала проверяет расширение этого файла. Это последняя часть имени файла, начинающаяся с .В случае файлов Python, это обычно .py.
  • Windows ищет, какое действие предпринять, основываясь на расширении файла.
    • Эта информация записана в реестре Windows; когда Python установлен, он обычно говорит Windows, что .pyфайлы должны быть открыты с помощью только что установленного приложения Python (то есть интерпретатора Python).
    • Несколько типов файлов имеют встроенное поведение; например, исполняемые файлы (такие как сам интерпретатор Python) должны заканчиваться .exe, а .batфайлы выполняются как пакетные сценарии Windows.
    • Действие, выполняемое для определенного типа файла, настраивается . Например, вы можете сказать Windows, что вместо запуска .pyфайлов python.exeследует открывать их с помощью другой программы, такой как текстовый редактор notepad.exe.
      • В этом случае, чтобы запустить скрипт Python, вам нужно будет вручную вызвать python <scriptname>.py(или написать .batфайл, чтобы сделать это для вас).

Теперь, что произойдет, если в верхней части скрипта Python есть строка Шебанга ( #!/usr/bin/pythonили #!/usr/bin/env python)? Ну, так #как это строка комментария в Python, интерпретатор Python просто игнорирует ее. Это одна из причин, почему большинство языков сценариев, используемых в мире Unix / Linux, используют #для запуска строк комментариев.

Поэтому немного ошибочно утверждать, что Windows «не нужна» #!строка; Окна не вижу в #!линию, а на самом деле опирается на расширение файла , чтобы сказать ему , что делать. Это имеет пару недостатков:

  • Вы должны назвать скрипты Python .pyв конце, чтобы они автоматически распознавались как таковые.
  • Нет простого способа отличить скрипты Python2 от скриптов Python3.
  • Как отмечалось ранее, если вы измените поведение запуска по умолчанию для .pyтипа файла, Windows больше не будет автоматически запускать эти сценарии с Python. Обратите внимание, что это может быть сделано непреднамеренно.

Теперь давайте посмотрим, как Unix / Linux запускает скрипты:

Первое, что следует отметить, это то, что Unix / Linux, в отличие от Windows, не пытается «открывать» скрипты Python с использованием определенной программы, по крайней мере, концептуально; ОС знает, что скрипт - это нечто, что может быть выполнено из-за чего-то, называемого «бит выполнения» (что выходит за рамки этого ответа). Таким образом, если вы случайно наберете #!/usr/bin/pthonвместо #!/usr/bin/python, вы получите сообщение об ошибке, содержащее этот текст:

/usr/bin/pthon: bad interpreter: No such file or directory.

Слово «интерпретатор» дает нам представление о роли линии Шебанга (хотя технически указанная программа может быть чем-то иным, чем интерпретатор, например catтекстовый редактор). Когда вы пытаетесь выполнить файл, вот что происходит:

  • Загрузчик программ Unix / Linux просматривает первые два байта этого файла; если эти два байта равны #!, то загрузчик интерпретирует остаток строки shebang (исключая сам shebang) как команду для запуска интерпретатора, с помощью которого содержимое файла запускается как скрипт.
  • Загрузчик программы запускает указанный интерпретатор, передавая ему путь исходного файла в качестве аргумента.

Это имеет пару преимуществ:

  • Автор сценария имеет больший контроль над тем, какой интерпретатор будет использоваться (что решает проблему Python2 / Python3), и иногда может передать дополнительный аргумент интерпретатору (подробности см. На странице Wiki).
  • Имя файла скрипта игнорируется , поэтому вы можете называть скрипты Python как хотите.

Наконец, обратите внимание, что Unix / Linux не нуждается в строке shebang для запуска скрипта Python. Вспомните, что на самом деле все, что делает строка shebang, это позволяет загрузчику программы выбрать интерпретатора. Но, как и в Windows, это можно сделать вручную:

python <myscript>

1
На Windows вы можете легко иметь .py2и .py3расширения для скриптов Python 2 / Python 3. Таким образом, и Linux (+ x bit), и Windows (расширение файла) нуждаются в метаданных в файловой системе. Основное отличие состоит в том, что бит + x легче теряется при передаче. Это не обязательно обратная сторона.
MSalters

1
@MSalters В бите выполнения также закодировано намного меньше информации. И обратите внимание, что у вас может быть несколько интерпретаторов Python2 в данной системе (аналогичная ситуация была с Ruby и другими языками на моей предыдущей работе); Работа с этим через линию Шебанга почти тривиальна, в то время как ситуация в Windows становится значительно менее понятной, чем больше вы пытаетесь управлять несколькими одинаковыми типами файлов.
Кайл Стрэнд,

Кроме того, действительно ли расширение считается "метаданными"? Это просто часть имени файла.
Кайл Стрэнд,

2
Метаданные файла включают в себя все имя файла, время создания, биты доступа и т. Д. Только сам контент представляет собой данные, а не метаданные. Что касается «множественных переводчиков», это действительно реальная проблема, и именно поэтому она не должна быть в строке Шебанга. Что делать, если у вас есть /usr/bin/i686/pythonи /usr/bin/amd64/python? Совершенно разумно, но это нарушает скрипты Python, которые имеют жестко запрограммированное предположение /usr/bin/python. Выбор переводчика зависит не от автора сценария, а от пользователя сценария. Автор сценария может выбирать только язык (диалект).
MSalters

1
@MSalters Ну вот для чего /usr/bin/env, вместе со скриптами env-setup. Что это за версия для Windows? Запускать regeditскрипт прямо перед запуском .pyфайла, чтобы убедиться, что вы получите нужный интерпретатор?
Кайл Стрэнд

41

Указанная вами строка используется, чтобы сообщить компьютеру, какую программу / интерпретатор использовать при непосредственном запуске файла / сценария, и любые аргументы, которые следует передать этой программе при запуске сценария. Это, однако, не требование Python , это требование ядра / системы linux, если вы собираетесь запустить скрипт напрямую (а не передавать его в Python с помощью приведенного ниже синтаксиса).

Это не нужно, если вы собираетесь выполнить python script.pyили подобное. Это необходимо только в том случае, если вы намереваетесь запустить скрипт / файл напрямую, без предоставления интерпретатора для использования (например, python).


Для сценария Bash это будет выглядеть примерно так:

#!/bin/bash [optional Bash arguments]
# Bash script code here
...
exit 0;

Это будет указывать системе, что при ее запуске она должна выполняться на /bin/bashодном из языков оболочки / сценариев оболочки в системе.


Для кода Python, однако, здесь вы захотите, чтобы исполняемый файл запускался через Python, поэтому вы сообщаете ему, какой интерпретатор вы собираетесь запустить в нем.

#!/usr/bin/python [optional Python arguments]
# Python code here
...
exit()

Это, как и для Bash, указывает, что /usr/bin/pythonследует использовать (это, вероятно, Python 2 или Python 3, в зависимости от конфигурации вашей отдельной системы).


Таким образом, вы можете запустить ./filename.pyили ./executableили ./scripttorunнапрямую.

Без этой строки в начале и при условии, что вы установили исполняемый файл / скрипт, и при условии, что вы работаете со скриптом Python, вам придется запускать python filename.pyили выполнять аналогичные функции, если у вас нет #!/usr/bin/pythonстроки. (Для сценария Bash вы должны будете сделать bash script.shили аналогичные для других сценариев / языков, таких как Perl, Ruby и т. Д.)

Выделение синтаксиса выше зависит от языка в каждом разделе, хотя это не имеет значения.


1
Интересно добавить, что после самого shebang можно указать дополнительные параметры, в большинстве случаев так же, как если бы интерпретатор вызывался напрямую ( #!/bin/bash -x, #!/usr/bin/perl -lanи т. Д.).
Кос

7
@kos: я думаю, что вы можете указать ровно один дополнительный аргумент, который был PITA, когда один (должен) использовать /usr/bin/env pythonдля получения правильного питона.
unperson325680

@progo Не уверен, в чем проблема env, но проблема не в количестве аргументов: #!/usr/bin/perl -l -a -nимеет три аргумента, но работает. Хотя, опять же, я не в состоянии справиться с точной проблемой.
Кос

При явном вызове интерпретатора со сценарием в качестве аргумента нет оснований начинать с последнего ./. Другими словами, просто python filename.pyили bash script.shбудет работать нормально. Единственная причина для включения ./- в имени команды, когда вы хотите, чтобы оболочка не выполняла поиск $PATH(который, вероятно, не найдет файлы в текущем каталоге), а указала путь, который вы указали как есть. Но это не относится к аргументам команды.
Марк ван Леувен

@kos: проблема может заключаться в том, как получить envостальные аргументы из ядра. Можно предположить, что все они являются одним большим аргументом без разбивки по пробелам. Извините за артикуляцию, я уже не помню подробностей этого
unperson325680

16

Линия:

#!/usr/bin/python

называется «шебанг» и указывает путь к двоичному файлу интерпретатора, который будет использоваться для интерпретации остальных команд в файле. Обычно это первая строка скрипта.

Таким образом, строка #!/usr/bin/pythonуказывает, что содержимое файла будет интерпретироваться pythonдвоичным файлом, расположенным в /usr/bin/python.

Обратите внимание, что строка shebang анализируется ядром, и затем сценарий будет в конечном итоге вызываться в качестве аргумента:

python script_name

Аналогично в случае #!/bin/bash:

bash script_name

2
Я не думаю, что когда-либо видел дефис в shebang. Поскольку слово образовано из «хэш» и «взрыв», ваше написание не очень ясно, так как похоже, что это сочетание «она» и «взрыв».
Кайл Стрэнд

Вы можете назвать его hashbang( #= "hash") или shebang( #= "sharp"), в зависимости от того, как вы назовете #персонажа. Тем не менее, shebangэто действительно чаще. @KyleStrand
Byte Commander

7

Технически это не требуется. Требуется путь к среде, в которой выполняется ваш скрипт. Ваши будущие сценарии лучше включить / usr / bin / env, а затем указать python. Это дает право на то, что ваш скрипт запускается в среде python независимо от того, где установлен python. Вы хотите сделать это по причинам совместимости, вы не можете быть уверены, что у следующего человека, с которым вы поделитесь своим кодом, будет установлен python в usr / bin / python, или что у них будут права доступа к этим системным файлам.

Вот аналогичные вопросы и ответы от переполнения стека .

Как это выглядит в вашем скрипте:

#!/usr/bin/env python

Я также вижу некоторую озабоченность по поводу того, как указать python3. Вот как это сделать:

#!/usr/bin/env python3

5

В Linux Python может требовать или не требовать #!строку (shebang). Это зависит от того, как обрабатываются коды Python: либо выполнение кодов в интерактивном режиме Python, либо в сценарии Python.

Интерактивный режим Python позволяет пользователю набирать и запускать коды Python напрямую, для чего не требуется строка shebang. Чтобы запустить интерактивный режим, откройте Терминал и введите pythonPython 2.X или python3Python 3.X.

$  python
Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

$  python3
Python 3.4.3 (default, Oct 14 2015, 20:33:09) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Сценарий Python позволяет пользователю писать и сохранять коды Python в виде простого текстового файла, а затем запускать коды позже. Это может или не может потребовать линии Шебанга. Однако есть две известные причины, по которым строка shebang требуется для использования скрипта Python в Linux.

  1. запускать коды Python в исполняемом скрипте, т.е. определять, как коды должны выполняться и какой интерпретатор использовать;

  2. запускать коды Python для определенной версии Python, т.е. запускать коды, совместимые только с Python 2.X или Python 3.X

Практикуйтесь со скриптами Python

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

$  ls -ln *.py
-rw-rw-r-- 1 1000 1000  94 Dec 14 18:37 hello1.py
-rwxrwxr-x 1 1000 1000 116 Dec 14 18:37 hello2e.py
-rw-rw-r-- 1 1000 1000 116 Dec 14 18:37 hello2.py
-rwxrwxr-x 1 1000 1000 117 Dec 14 18:37 hello3e.py
-rwxrwxr-x 1 1000 1000 120 Dec 14 18:37 hello3m.py
-rw-rw-r-- 1 1000 1000 117 Dec 14 18:37 hello3.py

$  file *.py
hello1.py:  ASCII text
hello2e.py: Python script, ASCII text executable
hello2.py:  Python script, ASCII text executable
hello3e.py: Python script, ASCII text executable
hello3m.py: Python script, UTF-8 Unicode (with BOM) text executable
hello3.py:  Python script, ASCII text executable
  • hello1.py содержит только исходный код

    import sys
    sys.stdout.write("Hello from Python %s\n" % (sys.version,))
    print("Hello, World!")
  • hello2.py содержит исходный код и строку Шебанга.

    #!/usr/bin/env python
    import sys
    sys.stdout.write("Hello from Python %s\n" % (sys.version,))
    print("Hello, World!")
  • hello2e.pyсодержит так же, как hello2.pyи исполняемый файл.

  • hello3.pyсодержит то же, что hello2.py, за исключением того, что он адаптирован для работы с Python 3 путем переименования первой строки в #!/usr/bin/env python3.

  • hello3e.pyсодержит так же, как hello3.pyи исполняемый файл.

  • hello3m.pyсодержит то же, что hello3.pyи исполняемый файл, за исключением того, что он сохранен с Write Unicode BOMопцией в текстовом редакторе, т.е.

Помимо этого, пользователю будут представлены два метода для запуска сценариев Python. Оба метода были продемонстрированы, как показано ниже.

Способ 1: запустить с помощью программы Python

Ниже приведены команды и вывод при запуске исходного кода с Python 2 и Python 3.

$  python hello1.py
Hello from Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2]
Hello, World!

$  python3 hello1.py
Hello from Python 3.4.3 (default, Oct 14 2015, 20:33:09) 
[GCC 4.8.4]
Hello, World!

Обе версии Python смогли успешно запустить скрипт. Следовательно, строка shebang не требуется при запуске скрипта Python с помощью pythonили python3команды.

Способ 2: запустить как скрипт Python

Ниже приведены команды и вывод при запуске исходного кода со строкой shebang, которые не адаптированы ни к Python 2, ни к Python 3, включая неисполнимые и исполняемые случаи.

$  ./hello1.py
bash: ./hello1.py: Permission denied

$  ./hello2.py
bash: ./hello2.py: Permission denied

$  ./hello3.py
bash: ./hello3.py: Permission denied

$  ./hello2e.py 
Hello from Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2]
Hello, World!

$  ./hello3e.py 
Hello from Python 3.4.3 (default, Oct 14 2015, 20:33:09) 
[GCC 4.8.4]
Hello, World!

Первые три сценария потерпели неудачу, потому что эти сценарии неисполняемы, независимо от наличия строки Шебанга или нет (Поддерживающее доказательство см. В дополнительном примере ниже). Последние два скрипта имеют строку shebang и являются исполняемыми.

Очевидно, что сценарий, который был сделан исполняемым, по сути бесполезен без строки shebang. Следовательно, требуется строка shebang, и сценарий должен быть исполняемым при запуске кодов Python в исполняемом сценарии.

Когда Шебанг не работает

В моем подготовленном и протестированном примере выполнение hello3m.pyв качестве исполняемого скрипта завершилось ошибкой и вернуло ошибку.

$  ./hello3m.py 
./hello3m.py: line 1: #!/usr/bin/env: No such file or directory

Это известное ограничение : шебанг не работает или становится недействительным. Когда файл сохраняется как Unicode BOM (Byte Order Mark), он не сможет нормально работать как исполняемый скрипт Python.

Дополнительный пример

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

Я создал еще один файл с именем hello1e.py, который содержит так же, как hello1.pyи сделал исполняемый файл. Запуск этого скрипта вернул синтаксическую ошибку.

$  ./hello1e.py 
./hello1e.py: line 2: syntax error near unexpected token `"Hello from Python %s\n"'
./hello1e.py: line 2: `sys.stdout.write("Hello from Python %s\n" % (sys.version,))'

При запуске этого скрипта, сначала курсор мыши изменится на знак плюс и ничего не будет делать по внешнему виду. Синтаксическая ошибка не будет отображаться, пока я не нажму на окно рабочего стола или терминала. Затем этот скрипт создаст sysфайл в том же каталоге, что и скрипт.

$  file sys
sys: PostScript document text conforming DSC level 3.0, Level 1

sysФайл был идентифицирован как файл PostScript, без расширения файла. Этот файл может быть открыт в средстве просмотра документов, т.е. Evince, и файл фактически содержит скриншот окна, которое я щелкнул ранее. По моему опыту, файл может быть размером до нескольких мегабайт.

Еще раз, строка shebang является обязательной, и сценарий должен быть исполняемым при запуске сценария Python в качестве исполняемого сценария. В противном случае скрипт будет работать неправильно, как описано выше.

Дополнительные примечания

Термин «сделан исполняемым» или «должен быть исполняемым» относится к разрешению на запуск сценария. Это можно сделать, запустив chmod +x FILENAMEкоманду в Терминале, или установив флажок «Разрешить запуск этого файла как программы» или что-то подобное в окне « Свойства» в файловом менеджере.

В то время как другие существующие ответы охватывали почти все, этот ответ использовал другой подход с использованием практических примеров для объяснения этого вопроса. Синтаксис кода был написан с осторожностью, так что примеры могут быть запущены с Python 2 или Python 3, как есть.

Коды Python были адаптированы с использованием Python для Windows и использования Python на платформах Unix с дополнительным однострочным кодом вездесущего «Hello, World!» программа.

Все коды и команды полностью протестированы и работают в системе Xubuntu 14.04, в которой по умолчанию установлены Python 2.7 и Python 3.4.


4

Это означает, что когда этот файл исполняется, ваш компьютер знает, как выполнить его с программой /usr/bin/python, это то, как вы говорите об этом, помимо другого языка, такого как bash, где вы будете делать #!/bin/bash. Это так, что вы можете просто запустить:

./[file-to-execute]

И он будет знать, с каким файлом его выполнять, а вам самим не придется указывать что-то вроде:

python ./[file-to-execute].py

Эта #!часть обычно называется шебанг или хруст .


2
Также hashbang.
Нафтули Кей

1

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

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

Это правило применимо только для систем на основе UNIX.


0

полезно для таких ОС, как Linux, где Python 2.x по-прежнему является стандартом, но большинство людей также скачивают 3.x.

2.x будет работать по умолчанию. Итак, мой код 3.x, я префикс #! / Usr / bin / env python3, чтобы 3.x запускал код. Я даже могу указать вплоть до незначительной ревизии (python 3.xyz), если я выбрал бета-версии или просто несколько более старые версии.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.