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