Почему поведение синтаксиса `#!` Не определено POSIX?


17

На странице языка команд оболочки спецификации POSIX:

Если первая строка файла команд оболочки начинается с символов «#!», Результаты не указываются.

Почему поведение #!не определено POSIX? Я нахожу странным, что что-то такое портативное и широко используемое будет иметь неопределенное поведение.


1
Стандарты оставляют вещи неопределенными, чтобы не привязывать реализации к конкретному поведению. Например, «логин» - это «неопределенное действие, с помощью которого пользователь получает доступ к системе».
— Кусалананда

2
Поскольку POSIX не указывает пути к исполняемым файлам, строка shebang в любом случае непереносима; Я не уверен, что многое можно было бы получить, указав это независимо.
— Майкл Гомер

1
@MichaelHomer, конечно нет? Стандарт может указывать, что строка содержит путь для интерпретатора, даже не указывая, каким должен быть этот путь.
— ilkkachu

1
@HaroldFischer За исключением того, что он не интерпретируется оболочкой, он интерпретируется либо ядром ОС (по крайней мере, в Linux, которое может фактически отключить эту поддержку во время сборки), либо любой другой библиотекой, реализующей exec()функцию. Поэтому проверка на наличие нескольких оболочек на самом деле не говорит вам, насколько она портативна.
— Остин Хеммельгарн

2
@HaroldFischer Более того, даже среди POSIX-совместимых операционных систем поведение не согласовано. Linux и macOS ведут себя по-разному: Linux не полностью разбивает строку shebang на пробелы. macOS не позволяет интерпретатору сценария быть другим сценарием. Также см en.wikipedia.org/wiki/Shebang_(Unix)#Portability
— jamesdlin

Ответы:


21

Я думаю, прежде всего потому, что:

  • поведение сильно варьируется в зависимости от реализации. Смотрите https://www.in-ulm.de/~mascheck/various/shebang/ для всех деталей.

    Однако теперь он может указывать минимальное подмножество большинства реализаций, подобных Unix: например, #! *[^ ]+( +[^ ]+)?\n(если в этих одном или двух словах заданы только символы из переносимого набора символов имени файла), когда первое слово представляет собой абсолютный путь к собственному исполняемому файлу, слишком длинный и поведение не определено, если исполняемый файл setuid / setgid, и реализация определяет, передается ли интерпретатору путь интерпретатора или путь сценария argv[0].

  • POSIX в любом случае не указывает путь к исполняемым файлам. В некоторых системах есть утилиты pre-POSIX в /bin/ /usr/binи утилиты POSIX где-то еще (как в Solaris 10, где /bin/shесть оболочка Bourne, а в POSIX - одна /usr/xpg4/bin; Solaris 11 заменил ее на ksh93, которая более совместима с POSIX, но большинство других инструменты /binвсе еще древние не POSIX). Некоторые системы не POSIX, но имеют режим / эмуляцию POSIX. Все, что требуется POSIX - это наличие документированной среды, в которой система ведет себя POSIXly.

    См. Например, Windows + Cygwin. На самом деле, с Windows + Cygwin, она взволнована, когда сценарий вызывается приложением cygwin, но не собственным приложением Windows.

    Таким образом, даже если в POSIX указан механизм shebang, его нельзя использовать для написания сценариев POSIX sh/ sed/ awk... (также обратите внимание, что механизм shebang нельзя использовать для написания надежного сценария sed/ awkсценария, так как он не позволяет передавать конец опции маркер).

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

По моему опыту, использование shebangs дает вам больше гарантий переносимости, чем использование POSIX-сценария написания сценариев оболочки: откажитесь от she-bang, напишите сценарий с shсинтаксисом POSIX и надейтесь, что все, что вызывает сценарий, вызывает для него POSIX-совместимость sh, хорошо, если вы знаете, что скрипт будет вызываться в правильной среде правильным инструментом, но не иначе.

Возможно, вам придется делать такие вещи, как:

#! /bin/sh -
if : ^ false; then : fine, POSIX system by default
else
  # cover Solaris 10 or older. ": ^ false" returns false
  # in the Bourne shell as ^ is an alias for | there for
  # compatibility with the Thomson shell.
  PATH=`getconf PATH`:$PATH; export PATH
  exec /usr/xpg4/bin/sh - "$0" ${1+"$@"}
fi
# rest of script

Если вы хотите быть переносимым на Windows + Cygwin, возможно , придется назвать свой файл с .batили .ps1расширением и использовать некоторый подобный трюк для cmd.exeили powershell.exeвызвать Cygwin shна том же файле.


Интересно, что из выпуска 5 : «Конструкция #! Зарезервирована для реализаций, желающих предоставить это расширение. Переносимое приложение не может использовать #! В качестве первой строки сценария оболочки; его нельзя интерпретировать как комментарий».
— Муру

@muru Если бы скрипт был действительно переносимым, в истинно POSIX-системе, работающей с POSIX sh, ему не понадобилась бы строка hashbang, как это было бы выполнено POSIX sh.
— Кусалананда

1
@Kusalananda, это правда только если execlpили execvpбыли использованы, верно? Если бы я использовал execve, это привело бы к ENOEXEC?
— Муру

9

[T] его поведение кажется согласованным между всеми оболочками жалоб POSIX. Я не вижу необходимости в комнате для маневра.

Вы не смотрите достаточно глубоко.

Еще в 1980 - х годах, этот механизм был не де - факто стандартизирован. Несмотря на то, что Деннис Ритчи это реализовал, эта реализация не достигла широкой публики в области AT & T во вселенной. Это было эффективно только публично доступно и известно в BSD; с исполняемыми сценариями оболочки, недоступными в AT & T Unix. Таким образом, было не разумно стандартизировать это. Положение вещей иллюстрируется этим современным документом, одним из многих таких:

Обратите внимание, что BSD позволяет #! interpreterнапрямую выполнять файлы, которые начинаются с , в то время как SysV позволяет напрямую выполнять только файлы .out. Это означает, что экземпляр одной из exec…()подпрограмм в программе BSD, возможно, придется изменить в SysV, чтобы /bin/shвместо этого выполнить интерпретатор (типично ) для этой программы.
- Стивен Фреде (1988). "Программирование в System X Release Y". Австралийский Unix Systems User Group Информационный бюллетень . Том 9. Номер 4. с. 111.

Важным моментом здесь является то, что вы смотрите на оболочки, в то время как наличие исполняемых сценариев оболочки на самом деле exec…()зависит от функций. То, что делают оболочки, включает в себя предшественники механизма исполняемых сценариев, которые все еще можно найти в некоторых оболочках даже сегодня (а также в настоящее время обязательные для exec…p()подмножества функций), и это несколько вводит в заблуждение. В этом отношении стандарт должен учитывать то, как exec…()работает интерпретируемый сценарий, и в то время, когда POSIX был изначально создан, он просто не работал в первую очередь в большей части спектра целевых операционных систем .

Подчиненный вопрос, почему это не было стандартизировано , так как, в частности , как механизм магического числа для сценария переводчиков был достигнута общественность в AT & T стороны Вселенной и был задокументирован для exec…()в определении 5 Интерфейса системы , на рубеже 1990 - х лет :

Файл интерпретатора начинается со строки вида

#! путь [arg]
где pathname - это путь интерпретатора, а arg - необязательный аргумент. Когда вы execиспользуете файл интерпретатора, система execиспользует указанный интерпретатор.
- exec. V Интерфейс Определение системы . Том 1. 1991.

К сожалению, поведение остается сегодня почти таким же широко расходящимся, как это было в 1980-х годах, и нет действительно распространенного поведения, которое можно стандартизировать. Некоторые Unices (например, HP-UX и FreeBSD, например) не поддерживают сценарии как интерпретаторы сценариев. То, является ли первая строка одним, двумя или многими элементами, разделенными пробелами, зависит от MacOS (и версий FreeBSD до 2005 года) и других. Максимальная поддерживаемая длина пути варьируется. ␀и символы из набора символов переносимого имени файла POSIX являются хитрыми, как начальные и конечные пробелы. То, чем заканчиваются 0-й, 1-й и 2-й аргументы, тоже сложно, со значительными различиями в разных системах. Некоторые в настоящее время POSIX-совместимые, но не- Системы Unix по-прежнему не поддерживают ни один такой механизм, и его обязательное преобразование приведет к тому, что они перестанут быть POSIX-совместимыми.

дальнейшее чтение


1

Как отмечается в некоторых других ответах, реализации различаются. Это затрудняет стандартизацию и сохранение обратной совместимости с существующими сценариями. Это верно даже для современных систем POSIX. Например, Linux не полностью разбивает строку shebang на пробелы. macOS не позволяет интерпретатору сценария быть другим сценарием.

Также смотрите http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability

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