#! / bin / sh -
Является (или, по крайней мере, было) часто рекомендуемым Шебангом для интерпретации сценария /bin/sh.
Почему не просто #! /bin/shили #!/bin/sh?
Для чего это -?
#! / bin / sh -
Является (или, по крайней мере, было) часто рекомендуемым Шебангом для интерпретации сценария /bin/sh.
Почему не просто #! /bin/shили #!/bin/sh?
Для чего это -?
Ответы:
По той же причине, по которой вам нужно написать:
rm -- *.txt
И нет
rm *.txt
Если вы не можете гарантировать, что ни один из .txtфайлов в текущем каталоге не имеет имени, начинающегося с -.
В:
рм <арг>
<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()и общее использование --для обозначения конца опций надолго. То, как оболочка Bourne (с конца 70-х) анализировала свои аргументы, рассматривался только первый аргумент для вариантов, если он начинался с -. Все символы после -будут рассматриваться как имена опций; если после персонажа не было персонажа -, вариантов не было. Это застряло, и все последующие Bourne-подобные оболочки признают -как способ обозначить конец вариантов.
В оболочке Bourne (но не в современных Bourne-подобных оболочках) #! /bin/sh -eufтакже можно обойти проблему, так как для вариантов был рассмотрен только первый аргумент.
Теперь, можно сказать , что мы быть педантичным здесь, и это также , почему я написал необходимость курсивом выше:
-или, +или помещать их в каталог, имя которого начинается с -или +.execvp()/ execlp()-типа. И в этом случае, как правило, вы вызываете их либо the-scriptдля поиска $PATHв этом случае, в этом случае аргумент пути к execve()системному вызову обычно начинается с /(не -ни +), либо, как ./the-scriptесли бы вы хотели, чтобы the-scriptв текущем каталоге выполнялся (и тогда путь начинается с ./, -ни с того , ни с +другого).Теперь, кроме проблемы теоретической правильности , есть еще одна причина, по которой он #! /bin/sh -стал рекомендоваться как хорошая практика . И это восходит ко времени, когда несколько систем все еще поддерживали сценарии setuid.
Если у вас есть скрипт, который содержит:
#! /bin/sh
/bin/echo "I'm running as root"
И этот сценарий был setuid 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-На них будут LookUp аргументы сценария , не /в $PATHхотя).
В настоящее время вряд ли какая-либо система поддерживает сценарий setuid, и некоторые из тех, которые все еще поддерживают (обычно не по умолчанию), в конечном итоге выполняют execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])(где <n>дескриптор файла открыт для чтения в сценарии), который работает как вокруг этой проблемы, так и состояние гонки.
Обратите внимание, что вы сталкиваетесь с похожими проблемами с большинством переводчиков, а не только с борновскими оболочками Оболочки, не похожие на Bourne, обычно не поддерживают -маркер конца опции, но обычно поддерживают --вместо этого (по крайней мере, для современных версий).
Также
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Не имею вопрос , как следующий аргумент рассматриваются как аргумент -fопции в любом случае, но он по- прежнему не работает , если path/to/scriptесть -(в этом случае, с большинством sed/ awkреализаций sed/ awkне читать код из -файл, но вместо стандартного ввода).
Также обратите внимание, что на большинстве систем нельзя использовать:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Как и в большинстве систем, механизм Шебанга допускает только один аргумент после пути интерпретатора.
Что касается использования #! /bin/sh -против #!/bin/sh -, это просто вопрос вкуса. Я предпочитаю первый, поскольку он делает путь интерпретатора более заметным и облегчает выбор мышью. Существует легенда, которая гласит, что место было необходимо в некоторых древних версиях Unix, но AFAIK, что никогда не проверялось.
Очень хорошая ссылка о Шебанге Unix может быть найдена в https://www.in-ulm.de/~mascheck/various/shebang
bashпринимает параметры, как и любая другая оболочка. Будучи Bourne-подобной и POSIX-оболочкой, bashпринимает как #! /bin/bash -и #! /bin/bash --.