В bash
или sh
, я предполагаю , что все , что начинается с #
это комментарий .
Но в bash
скриптах мы пишем:
#!/bin/bash
А в скриптах Python есть:
#!/bin/python
Означает ли это, что #
сам по себе является комментарием, а #!
нет?
В bash
или sh
, я предполагаю , что все , что начинается с #
это комментарий .
Но в bash
скриптах мы пишем:
#!/bin/bash
А в скриптах Python есть:
#!/bin/python
Означает ли это, что #
сам по себе является комментарием, а #!
нет?
Ответы:
#!
Линия используется , прежде чем скрипт запускается, то игнорируется при выполнении сценария.Вы спрашиваете, в чем разница между строкой Шебанга и обычным комментарием.
Строка, начинающаяся с #!
такого же комментария, как и любая другая строка, начинающаяся с #
. Это верно, если #!
первая строка файла или где-либо еще. #!/bin/sh
имеет эффект , но он не читается самим переводчиком .
#
это не комментарий во всех языках программирования, но, как вы знаете, это комментарий в оболочках в стиле Борна, включая sh
и bash
(а также в большинстве оболочек не в стиле Борна, например csh
). Это также комментарий в Python . И это комментарий в различных конфигурационных файлах, которые вообще не являются сценариями (например /etc/fstab
).
Предположим, что сценарий оболочки начинается с #!/bin/sh
. Это комментарий, и интерпретатор (оболочка) игнорирует все в строке после #
символа.
Цель #!
строки - не предоставлять информацию переводчику. Цель этой #!
строки - сообщить операционной системе (или какому-либо процессу, запускающему интерпретатор), что использовать в качестве интерпретатора .
Если вы вызываете сценарий как исполняемый файл, например, запустив его ./script.sh
, система обращается к первой строке, чтобы узнать, начинается ли с #!
нее, после которой идет ноль или более пробелов, после чего следует команда. Если это так, он запускает эту команду с именем сценария в качестве аргумента. В этом примере он запускается /bin/sh script.sh
(или, технически, /bin/sh ./script.sh
).
Если вы вызываете сценарий, явно вызывая интерпретатор, к #!
строке никогда не обращаются. Так что, если вы запустите sh script.sh
, первая строка не имеет никакого эффекта. Если script2.sh
первая строка #!/usr/games/nibbles
, запуск sh script2.sh
не будет пытаться открыть скрипт nibbles
(но ./script2.sh
будет).
Вы заметите, что ни в том, ни в другом случае расширение скрипта ( .sh
), если оно есть, не влияет на его выполнение. В Unix-подобных системах это обычно не влияет на работу скрипта. В некоторых других системах, таких как Windows, система #!
может полностью игнорировать строку shebang, и расширение может определять, какие сценарии выполняются. (Это не означает, что вам нужно давать расширения для скриптов, но это одна из причин, почему, если вы это сделаете, они должны быть правильными.)
#!
был выбран для этой цели именно потому, что #
начинается комментарий. #!
Линия для системы, а не переводчик, и он должен быть проигнорирован интерпретатором.
Вы (изначально) сказали, что используете #!/bin/sh
для bash
сценариев. Вы должны делать это только в том случае, если сценарий не требует каких-либо bash
расширений - sh
должен иметь возможность запускать сценарий. sh
не всегда символическая ссылка на bash
. Зачастую, в том числе во всех удаленно современных системах Debian и Ubuntu , sh
есть символическая ссылка на dash
.
Вы также сказали (в первой версии вашего вопроса, перед редактированием), что запускаете свои скрипты Python #!/bin/sh read by the interpretor
. Если вы имеете это в виду буквально, то вам определенно следует прекратить это делать. Если hello.py
начинается с этой строки, выполняется ./hello.py
run:
/bin/sh read by the interpretor hello.py
/bin/sh
попытается выполнить скрипт с именем read
(в by the interpretor hello.py
качестве аргумента), read
(надеюсь) не будет найден, и ваш скрипт Python никогда не будет виден интерпретатором Python.
Если вы делаете эту ошибку, но у меня нет проблемы, которую я описываю, вы, вероятно, вызываете свои скрипты Python, явно указывая интерпретатор (например, python hello.py
), в результате чего первая строка игнорируется. Когда вы распространяете свои сценарии среди других или используете их долгое время спустя, может быть неясно, что это необходимо для их работы. Лучше исправить это сейчас. Или, по крайней мере, удалите первую строку целиком, чтобы, когда они не запускаются, ./
сообщение об ошибке имело смысл.
Для скриптов Python, если вы знаете, где находится (или будет) интерпретатор Python, вы можете написать #!
строку так же:
#!/usr/bin/python
Или, если это скрипт на Python 3, вы должны указать python3
, так как python
это почти всегда Python 2 :
#!/usr/bin/python3
Однако проблема заключается в том, что, хотя /bin/sh
предполагается, что он всегда существует и /bin/bash
почти всегда существует в системах, где bash
поставляется ОС, Python может существовать в разных местах.
Поэтому многие программисты Python используют это вместо:
#!/usr/bin/env python
(Или #!/usr/bin/env python3
для Python 3.)
Это заставляет сценарий полагаться на то, env
чтобы быть в «правильном месте» вместо того, чтобы полагаться на то, python
чтобы быть в правильном месте. Это хорошо, потому что:
env
почти всегда находится в /usr/bin
.python
должен запускаться первым PATH
. Начиная hello.py
с #!/usr/bin/env python
make ./hello.py
run /usr/bin/env python hello.py
, что (практически) эквивалентно запуску python hello.py
.Причина, по которой вы не можете использовать #!python
это:
/
).python
в текущем каталоге . Поиск пути, когда команда не содержит косой черты, является специфическим поведением оболочки.Иногда Python или другой сценарий, который не является сценарием оболочки, будет содержать строку shebang, начинающуюся с #!/bin/sh ...
где- ...
то другого кода. Иногда это правильно, потому что есть несколько способов вызвать Bourne-совместимую оболочку ( sh
) с аргументами, чтобы заставить ее вызывать интерпретатор Python. (Один из аргументов, вероятно, будет содержать python
.) Однако для большинства целей #!/usr/bin/env python
он проще, элегантнее и с большей вероятностью будет работать так, как вы хотите.
Многие языки программирования и сценариев, а также некоторые другие форматы файлов используют #
в качестве комментариев. Для любого из них файл на языке может быть запущен программой, которая принимает его в качестве аргумента, указав программу в первой строке после #!
.
В некоторых языках программирования #
это обычно не комментарий, но в особом случае первая строка игнорируется, если начинается с #!
. Это облегчает использование #!
синтаксиса, хотя в #
противном случае не делает строку комментарием.
Хотя он менее интуитивен, любой файл, формат файла которого может вместить первую строку, начинающуюся с #!
полного пути исполняемого файла, может иметь строку shebang. Если вы сделаете это, и файл будет помечен как исполняемый, то вы можете запустить его как программу ... вызывая его открытие как документ.
Некоторые приложения используют это поведение намеренно. Например, в VMware .vmx
файлы определяют виртуальные машины. Вы можете «запустить» виртуальную машину, как если бы это был скрипт, потому что эти файлы помечены как исполняемые и имеют строку shebang, вызывающую их открытие в утилите VMware.
rm
удаляет файлы Это не язык сценариев. Однако файл, который запускается #!/bin/rm
и помечается как исполняемый, может быть запущен, и при запуске он rm
вызывается для него, удаляя его.
Это часто концептуализируется как «файл удаляет сам себя». Но файл на самом деле не работает. Это больше похоже на ситуацию, описанную выше для .vmx
файлов.
Тем не менее, поскольку #!
строка облегчает выполнение простой команды (включая аргументы командной строки), вы можете выполнить некоторые сценарии таким образом. В качестве простого примера более сложного «сценария» #!/bin/rm
рассмотрим:
#!/usr/bin/env tee -a
Это принимает пользовательский ввод в интерактивном режиме, выводит его обратно пользователю построчно и добавляет его в конец файла «script».
Полезно? Не очень. Концептуально интересно? Полностью! Да. (В некотором роде.)
Скрипты / программы на нескольких языках одновременно , например, для имитации функциональности hashbang в ОС, в которых ее нет .
(Эти программы называются полиглоты , но это не следует путать с другим смыслом полиглота в разработке программного обеспечения , программы / проекта, где разные части написаны на разных языках.)
Метакоманды в QBasic / QuickBASIC, которые сообщали компилятору (для скомпилированного кода) опции для генерации кода, но были частью комментариев и, таким образом, игнорировались при фактической компиляции / интерпретации.
-x
флаг Pythons ?
-x
«скип [s] первая строка ...» 2 - я линия получает пронумерованные 1
вместо 2
, 3 - я линия , 2
а не 3
, и т.д. Вот почему вы не должны использовать этот флаг. ;) -x
предназначен для написания сценариев в не-Unix-подобных ОС, которые имеют шебангоподобный синтаксис, не начинающийся с #
(таким образом, не комментарий Python).
perl script.pl
против ./script.pl
) , то интерпретатор будет читать строку притона для синтаксического анализа флагов , таких как -w
. Однако не рекомендуется полагаться на эту функцию.
Шебанг - это последовательность символов, состоящая из знака числа символов и восклицательного знака (например, «#!»), Когда она встречается в качестве начальных двух символов в начальной строке скрипта.
В операционных системах * nix, когда запускается скрипт, начинающийся с shebang, загрузчик программы анализирует остальную часть начальной строки скрипта как директиву интерпретатора; вместо этого запускается указанная программа-интерпретатор, передавая ей в качестве аргумента путь, который изначально использовался при попытке запустить скрипт. Например, если сценарий назван с путем «path / to / your-script», и он начинается со следующей строки:
#!/bin/sh
затем загрузчик программы получает указание запустить программу "/ bin / sh", например, например, оболочку Bourne или совместимую оболочку, передавая "путь / к / вашему скрипту" в качестве первого аргумента.
Соответственно, скрипт называется с путем «путь / к / python-скрипт» и начинается со следующей строки:
#!/bin/python
Затем загруженная программа получает указание запустить программу «/ bin / python», например, интерпретатор Python, передавая «путь / to / python-script» в качестве первого аргумента.
Короче "#" закомментирует строку, а последовательность символов "#!" встречается как первые два символа в начальной строке скрипта, как указано выше.
Подробнее см. Почему некоторые скрипты начинаются с #! ...?
Источник: некоторые разделы этого ответа получены (с небольшими изменениями) из Шебанга (Unix) в английской Википедии ( авторами Википедии ). Эта статья лицензирована в соответствии с CC-BY-SA 3.0 , так же, как пользовательский контент здесь, на AU, поэтому этот вывод разрешен с указанием авторства.
#!
вызывается, shebang
когда он встречается в качестве начальных двух символов в начальной строке скрипта. Он используется в скриптах для указания интерпретатора для выполнения. Это shebang
для операционной системы (ядра), а не для оболочки; поэтому он не будет интерпретироваться как комментарий.
Предоставлено: http://en.wikipedia.org/wiki/Shebang_%28Unix%29
В общем, если файл является исполняемым, но на самом деле не исполняемой (двоичной) программой, и такая строка присутствует, программа указывается после #! запускается с именем скрипта и всеми его аргументами. Эти два символа # и! должны быть первые два байта в файле!
Подробная информация: http://wiki.bash-hackers.org/scripting/basics#the_shebang
Нет, он используется только exec
системным вызовом ядра Linux и рассматривается интерпретатором как комментарий
Когда вы делаете на 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, правильно помещает его в память и запускает новый процесс с ним. Смотрите также: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Наконец, вы можете добавить свои собственные обработчики shebang с binfmt_misc
механизмом. Например, вы можете добавить пользовательский обработчик для .jar
файлов . Этот механизм даже поддерживает обработчики по расширению файла. Другое приложение - для прозрачного запуска исполняемых файлов другой архитектуры с QEMU .
Я не думаю, что POSIX определяет shebangs, однако: https://unix.stackexchange.com/a/346214/32558 , хотя он упоминается в разделах обоснования и в форме «если исполняемые сценарии поддерживаются системой, что-то может случиться».
#include
. Там тоже#
не подразумевается как комментарий.