#! / бін / ш -
Часто рекомендований шебанг є (або принаймні був), щоб інтерпретувати сценарій /bin/sh.
Чому б не просто #! /bin/shчи #!/bin/sh?
Для чого це -?
#! / бін / ш -
Часто рекомендований шебанг є (або принаймні був), щоб інтерпретувати сценарій /bin/sh.
Чому б не просто #! /bin/shчи #!/bin/sh?
Для чого це -?
Відповіді:
Це з аналогічної причини, чому потрібно писати:
rm -- *.txt
І ні
rm *.txt
Якщо ви не можете гарантувати, що жоден з .txtфайлів у поточному каталозі не має імені, з якого починається -.
В:
rm <arg>
<arg>вважається варіантом, якщо він починається з -або видалити файл в іншому випадку. В
rm - <arg>
argзавжди вважається файлом для видалення незалежно від того, починається він -чи ні.
Це те саме для sh.
Коли виконується сценарій, який починається з
#! /bin/sh
Як правило:
execve("path/to/the-script", ["the-script", "arg"], [environ])
Система перетворює його на:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
Зазвичай path/to/the-scriptце не те, що знаходиться під контролем автора сценарію. Автор не може передбачити, де зберігатимуться копії сценарію, ні під яким іменем. Зокрема, вони не можуть гарантувати, що з того, path/to/the-scriptз чим він викликається, не почнеться -(або з чим +це теж проблема sh). Ось чому ми потрібні- тут , щоб відзначити кінець опцій.
Наприклад, у моїй системі zcat(як і у більшості інших сценаріїв насправді) є один приклад сценарію, який не дотримувався цієї рекомендації:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Тепер ви можете запитати, чому #! /bin/sh -ні #! /bin/sh --?
Хоча #! /bin/sh --би працював із оболонками POSIX, той #! /bin/sh -більш портативний; зокрема до стародавніх версій о sh. shтрактування -як і попередніх варіантів закінчення варіанта, getopt()і загальне використання --для довготривалого позначення кінця варіантів. Те, як оболонка Борна (з кінця 70-х) розбирала свої аргументи, лише перший аргумент вважався варіантами, якщо він починався з -. Усі символи після -вважатимуться іменами опцій; якщо не було символу після -, не було варіантів. Це застрягло, і всі пізніші оболонки Борна розпізнають -як спосіб позначити кінець варіантів.
У оболонці Борна (але не в сучасних оболонках, схожих на Борна), #! /bin/sh -eufтакож було б вирішено проблему, оскільки лише перший аргумент розглядався як варіант.
Тепер можна сказати, що ми тут робимо педантичний характер, і саме тому я написав необхідність курсивом вище:
-або +або помістити їх в каталог, ім'я якого починається з -або +.execvp()/ execlp()-тип функцій. І в такому випадку, як правило, ви викликаєте їх або the-scriptдля того, щоб його шукали, і в $PATHцьому випадку аргумент шляху до execve()системного виклику зазвичай починається з /(ні -норм +) або так, як ./the-scriptякщо ви хочете the-scriptв поточному каталозі запускатися (і тоді шлях починається з ./ні, -ні з +них).Тепер, крім питання теоретичної коректності , є ще одна причина, чому її #! /bin/sh -рекомендують використовувати як добру практику . І це повертається до часу, коли кілька систем все ще підтримували встановлені сценарії.
Якщо у вас є сценарій, який містить:
#! /bin/sh
/bin/echo "I'm running as root"
І цей скрипт був встановлений корінь (як і з -r-sr-xr-x root binдозволами), в тих системах, коли виконується звичайним користувачем,
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
буде зроблено як root!
Якщо користувач створив симпосилання /tmp/-i -> path/to/the-scriptі виконав його як -i, він запустив б інтерактивну оболонку ( /bin/sh -i) як root.
Це -дозволить обійтись (це не обійдеться з питаннями про стан перегонів або з тим, що деякі shреалізації, як-от такі, які ksh88базуються на основі, шукатимуть аргументи сценарію без того, /щоб $PATHвсе-таки було).
В даний час навряд чи будь-яка система підтримує встановлений сценарій, і деякі з тих, що все ще роблять (як правило, не за замовчуванням), в кінцевому підсумку роблять execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])(де <n>дескриптор файлів відкритий для читання в сценарії), який працює як над цією проблемою, так і стан перегонів.
Зауважте, що у вас виникають подібні проблеми з більшістю перекладачів, а не тільки з оболонками Борна. Оболонки, не подібні до Борна, як правило, не підтримують -як маркер кінця опції, але, як правило, підтримують --(принаймні, для сучасних версій).
Також
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Не майте проблеми, оскільки наступний аргумент розглядається як аргумент до -fпараметра в будь-якому випадку, але він все ще не працює, якщо path/to/scriptє -(у такому випадку, з більшості sed/ awkреалізацій, sed/ awkне читайте код з -файл, але замість stdin).
Також зверніть увагу, що в більшості систем не можна використовувати:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Як і в більшості систем, механізм shebang дозволяє лише один аргумент після шляху інтерпретатора.
Що стосується використання #! /bin/sh -vs #!/bin/sh -, це лише питання смаку. Я віддаю перевагу першому, оскільки це робить шлях перекладача більш помітним і полегшує вибір миші. Існує легенда, яка говорить про те, що місце було потрібно в деяких старовинних версіях Unix, однак AFAIK, що ніколи не було перевірено.
Дуже хороший довідник про шебанг Unix можна знайти на https://www.in-ulm.de/~mascheck/various/shebang
bashприймає параметри, як і всі інші оболонки. Будучи оболонкою Борна і POSIX, bashприймає і те, #! /bin/bash -і #! /bin/bash --.