#! / Bin / sh читается переводчиком?

В bash или sh, я думаю, все, что начинается с #, является комментарием .

Но в bash сценариях мы пишем:

#!/bin/bash

А в сценариях Python есть:

#!/bin/python

Означает ли это, что # сам по себе является комментарием тогда как #! нет?

66
задан 9 January 2013 в 11:46

4 ответа

#! строка используется, прежде чем скрипт запущен, затем проигнорирован, когда сценарий работает.

Вы спрашиваете, что различие между строкой хижины и обычным комментарием.

Строка, запускающаяся с #! так же комментарий как любая другая строка, которая запускается с #. Это верно если #! первая строка файла, или где-либо еще. #!/bin/sh имеет эффект, но он не читается самим интерпретатором.

# не комментарий на всех языках программирования, но, как Вы знаете, это - комментарий в оболочках стиля Границы включая sh и bash (а также большинство оболочек non-Bourne-style, как csh). Это - также комментарий в Python. И это - комментарий во множестве конфигурационных файлов, которые не являются действительно сценариями вообще (как /etc/fstab).

Предположим, что сценарий оболочки начинается #!/bin/sh. Это - комментарий, и интерпретатор (оболочка) игнорирует все на строке после # символ.

Цель a #! строка не должна давать информацию интерпретатору. Цель #! строка должна сказать операционную систему (или независимо от того, что процесс запускает интерпретатор), что использовать в качестве интерпретатора.

  • Если Вы вызываете сценарий как исполняемый файл, например, путем выполнения ./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, #! строка хижины могла бы быть проигнорирована полностью системой, и расширение могло бы определить то, что запускает скрипты. (Это не означает, что необходимо дать расширения сценариев, но это - одна из причин, почему, если Вы делаете, они должны быть корректными.)

#! был выбран для служения этой цели точно потому что # начинает комментарий. #! строка для системы, не интерпретатора, и это должно быть проигнорировано интерпретатором.

Строка хижины для сценариев Bash

Вы (первоначально) сказали, что используете #!/bin/sh для bash сценарии. Необходимо только сделать это, если сценарий не требует ни одного из bashрасширения-sh потребности смочь запустить скрипт. sh не всегда символьная ссылка на bash. Часто, включая на всем удаленно недавнем Debian и системах Ubuntu, sh символьная ссылка на dash.

Строка хижины для сценариев Python

Вы также сказали (в первой версии Вашего вопроса, прежде, чем отредактировать) запуск сценариев Python с #!/bin/sh read by the interpretor. Если Вы подразумеваете, что буквально, то необходимо определенно прекратить делать это. Если hello.py начинается с той строки, работая ./hello.py выполняется:

/bin/sh read by the interpretor hello.py

/bin/sh попытается выполнить названный сценарий readby 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 сделать ./hello.py выполненный /usr/bin/env python hello.py, который (фактически) эквивалентен выполнению python hello.py.

Причина Вы не можете использовать #!python это:

  • Вы хотите интерпретатор, указанный, чтобы быть данными полным путем (т.е. запускающийся с /).
  • Обработка вызовов выполнилась бы python в текущем каталоге. Поиск пути, когда команда не содержит наклонную черту, является определенным поведением оболочки.

Иногда Python или другой сценарий, который не является сценарием оболочки, будут иметь строку хижины, запускающуюся с #!/bin/sh ... где ... некоторый другой код. Это иногда корректно, потому что существуют некоторые способы вызвать Совместимую с границей оболочку (sh) с аргументами, чтобы заставить его вызвать интерпретатор Python. (Один из аргументов будет, вероятно, содержать python.) Однако в большинстве целей, #!/usr/bin/env python более просто, более изящен, и более вероятно работать способ, которым Вы хотите.

Строки хижины на других языках

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

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

Строки хижины для файлов, которые не работают как сценарии

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

Некоторые приложения используют это поведение намеренно. Например, в VMware, .vmx файлы определяют виртуальные машины. Можно "выполнить" виртуальную машину, как будто это был сценарий, потому что эти файлы отмечены исполняемый файл и имеют строку хижины, заставляющую их быть открытыми в утилите VMware.

Строки хижины для файлов, которые не работают как документы на получение, но закон как сценарии так или иначе

rm удаляет файлы. Это не язык сценариев. Однако файл, который запускается #!/bin/rm и отмечен, исполняемый файл может быть выполнен, и когда Вы выполняете его, rm вызывается на него, удаляя его.

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

Однако, потому что #! строка упрощает выполнение простой команды (включая параметры командной строки), можно выполнить некоторые сценарии этого пути. Как простой пример "сценария", более сложного, чем #!/bin/rm, рассмотрите:

#!/usr/bin/env tee -a

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

Полезный? Не очень. Концептуально интересный? Полностью! Да. (Несколько).

Концептуально Подобные Понятия Программирования/Сценариев (только для забавы)

100
ответ дан 9 January 2013 в 11:46

Нет, это только используется exec системный вызов ядра Linux, и рассматривал как комментарий интерпретатора

Когда Вы делаете на ударе:

./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

Наконец, можно добавить собственные обработчики хижин с binfmt_misc механизм. Например, можно добавить пользовательский обработчик для .jar файлы. Этот механизм даже поддерживает обработчики расширением файла. Другое приложение должно прозрачно выполнить исполняемые файлы другой архитектуры с QEMU.

Я не думаю, что POSIX указывает хижины однако: https://unix.stackexchange.com/a/346214/32558, хотя это действительно упоминает в на разделах объяснения, и в форме, "если исполняемые сценарии поддерживаются системой, что-то может произойти".

0
ответ дан 9 January 2013 в 11:46

Хижина является последовательностью символов, состоящей из знака номера символов и восклицательного знака (например, "#!"), когда это происходит как начальные два символа на начальной строке сценария.

Под *отклоняют операционные системы, когда скрипт, запускающийся с хижины, запущен, загрузчик программы анализирует остальную часть начальной строки сценария как директива интерпретатора; указанная программа интерпретатора запущена вместо этого, передав ему как аргумент путь, который первоначально использовался при попытке запустить скрипт. Например, если сценарий называют с путем "path/to/your-script", и он запускается со следующей строки:

#!/bin/sh

затем загрузчик программы проинструктирован для запущения программы "/bin/sh" вместо этого, например, Оболочки Bourne или совместимой оболочки, передав "path/to/your-script" как первый аргумент.

Соответственно, это, которым сценарий называют с путем "path/to/python-script" и он запускается со следующей строки:

#!/bin/python

затем загруженная программа проинструктирована для запущения программы "/bin/python" вместо этого, например, интерпретатора Python, передав "path/to/python-script" как первый аргумент.

Короче говоря "#" прокомментирует строку в то время как последовательность символов "#!" появление как первые два символа на начальной строке сценария имеет значение, обрисованное в общих чертах как выше.

Для получения дополнительной информации посмотрите, Почему делают некоторые сценарии запускаются с #!...?

Источник: Некоторые разделы этого ответа получены (с небольшой модификацией) от Хижины (Unix) на английскую Википедию (участниками Википедии). Эта статья лицензируется под CC SA 3.0, то же как пользовательское содержание здесь на AU, таким образом, эта деривация разрешена с атрибуцией.

7
ответ дан 9 January 2013 в 11:46

#! называется shebang, когда он встречается в качестве начальных двух символов в начальной строке скрипта. Он используется в сценариях для обозначения интерпретатора для выполнения. shebang предназначен для операционной системы (ядра), а не для оболочки; поэтому он не будет интерпретироваться как комментарий.

Предоставлено: http://en.wikipedia.org/wiki/Shebang_%28Unix%29

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

Подробная информация: http://wiki.bash-hackers.org/scripting/basics#the_shebang

0
ответ дан 9 January 2013 в 11:46

Другие вопросы по тегам:

Похожие вопросы: