Чому поведінка синтаксису `#!` Не визначена POSIX?


17

На сторінці мови командної оболонки специфікації POSIX:

Якщо перший рядок файлу команд оболонки починається з символів "#!", Результати не визначені.

Чому поведінка #!не визначена POSIX? Мені здається, що бентежить, що щось настільки портативне та широко застосовуване може мати не визначену поведінку.


1
Стандарти залишають речі не визначеними, щоб не прив'язувати реалізацію до певної поведінки. Наприклад, "вхід" - це "Не визначена діяльність, завдяки якій користувач отримує доступ до системи".
Kusalananda

2
Оскільки POSIX не визначає виконавчі шляхи, лінія shebang за своєю суттю не є портативною; Я не впевнений, що багато чого можна отримати, уточнивши його незалежно.
Майкл Гомер

1
@MichaelHomer, точно не? Стандарт може вказати, що рядок містить шлях, який слід використати для інтерпретатора, навіть не кажучи про те, яким повинен бути цей шлях.
ilkkachu

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

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

Відповіді:


21

Я думаю насамперед тому, що:

  • поведінка сильно різниться між реалізацією. Дивіться https://www.in-ulm.de/~mascheck/various/shebang/ для всіх подробиць.

    Тепер він міг би вказати мінімальний підмножина більшості Unix-подібних реалізацій: наприклад #! *[^ ]+( +[^ ]+)?\n(із лише символами з переносного символу назви файлу, встановленого в тих чи двох словах), де перше слово є абсолютним шляхом до нативного виконуваного файлу, річ не в тому занадто довгий і поведінка не визначена, якщо виконуваний файл встановлений / 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, - це наявність документально підтвердженого середовища, в якому система поводиться POSIX.

    Наприклад, див. Windows + Cygwin. Насправді, для Windows + Cygwin, вона чудована, коли скрипт викликається програмою cygwin, але не рідною програмою Windows.

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

Тепер факт, що він не визначений, не означає, що ви не можете його використовувати (ну, це говорить, що ви не повинні починати перший рядок, #!якщо ви очікуєте, що це буде лише звичайний коментар, а не шум), але що POSIX не дає вам гарантії, якщо ви зробите це.

З мого досвіду, використання shebangs дає більше гарантії портативності, ніж використання способу написання сценаріїв оболонки POSIX: відмовтеся від she-bang, напишіть сценарій у shсинтаксисі POSIX і сподівайтеся, що все, що викликає сценарій, викликає сумісний shз ним POSIX , який є добре, якщо ви знаєте, що правильний інструмент буде викликаний у потрібному середовищі, але не інакше.

Можливо, вам доведеться робити такі речі, як:

#! /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, йому не знадобиться лінія хешбангу, як це буде виконуватися POSIX sh.
Кусалаланда

1
@Kusalananda це вірно тільки в тому випадку , execlpабо execvpбули використані, НЕ так? Якби я був використаний execve, це призведе до ENOEXEC?
муру

9

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

Ви не дивитесь досить глибоко.

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

Зауважте, що BSD дозволяє файли, які починаються з #! interpreterвиконання, безпосередньо, тоді як SysV дозволяє виконувати лише a.out файли безпосередньо. Це означає, що екземпляр однієї з exec…()підпрограм у програмі BSD, можливо, доведеться змінити під SysV, щоб /bin/shзамість цього виконати інтерпретатор (типово ) для цієї програми.
- Стівен Фред (1988). Msgstr "Програмування на випуску системи X". Australian Unix Systems User Group Newsletter . Том 9. № 4. с. 111.

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

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

Файл перекладача починається з рядка форми

#! ім'я шляху [arg]
де ім'я шляху - шлях інтерпретатора, а арг - необов'язковий аргумент. Коли ви execперекладаєте файл перекладача, система execвикористовує вказаний інтерпретатор.
- exec. V Інтерфейс Визначення системи . Том 1. 1991 рік.

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

Подальше читання


1

Як зазначається в деяких інших відповідях, реалізація відрізняється. Це ускладнює стандартизацію та збереження зворотної сумісності з існуючими сценаріями. Це справедливо навіть для сучасних систем POSIX. Наприклад, Linux не повністю токенізує лінію шебанга пробілами. macOS не дозволяє інтерпретатору сценарію бути іншим сценарієм.

Також дивіться http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.