#! / bin / sh -
É (ou pelo menos foi) geralmente o shebang recomendado para interpretar um script /bin/sh
.
Por que não apenas #! /bin/sh
ou #!/bin/sh
?
Para que é isso -
?
fonte
#! / bin / sh -
É (ou pelo menos foi) geralmente o shebang recomendado para interpretar um script /bin/sh
.
Por que não apenas #! /bin/sh
ou #!/bin/sh
?
Para que é isso -
?
É por um motivo semelhante ao por que você precisa escrever:
rm -- *.txt
E não
rm *.txt
A menos que você possa garantir que nenhum dos .txt
arquivos no diretório atual tenha um nome que comece com -
.
Em:
rm <arg>
<arg>
é considerado uma opção se iniciar com -
ou um arquivo para remover de outra forma. Em
rm - <arg>
arg
é sempre considerado como um arquivo a ser removido, independentemente de iniciar -
ou não.
É o mesmo para sh
.
Quando alguém executa um script que começa com
#! /bin/sh
Normalmente com:
execve("path/to/the-script", ["the-script", "arg"], [environ])
O sistema o transforma em:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
A path/to/the-script
geralmente não é algo que está sob o controle do autor script. O autor não pode prever onde as cópias do script serão armazenadas nem com que nome. Em particular, eles não podem garantir que o modo path/to/the-script
como é chamado não comece -
(ou +
que também seja um problema sh
). É por isso que precisamos do -
aqui para marcar o final das opções.
Por exemplo, no meu sistema zcat
(como a maioria dos outros scripts, na verdade) é um exemplo de script que não seguiu essa recomendação:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Agora você pode perguntar por que #! /bin/sh -
e não #! /bin/sh --
?
Embora #! /bin/sh --
funcionasse com shells POSIX, o #! /bin/sh -
é mais portátil; em particular para versões antigas de sh
. sh
tratar -
como e o final da opção é anterior getopt()
e o uso geral de --
para marcar o final das opções por um longo tempo. Da maneira como o shell Bourne (do final dos anos 70) analisou seus argumentos, apenas o primeiro argumento foi considerado para as opções se ele começou com ele -
. Todos os caracteres a seguir -
seriam tratados como nomes de opções; se não houvesse caracteres após o -
, não havia opções. Isso ficou preso e todas as conchas semelhantes a Bourne mais tarde reconhecem -
como uma maneira de marcar o fim das opções.
No shell Bourne (mas não nos modernos cascos Bourne), #! /bin/sh -euf
também contornaria o problema, pois apenas o primeiro argumento foi considerado para opções.
Agora, pode-se dizer que estamos sendo pedantes aqui, e também é por isso que escrevi a necessidade em itálico acima:
-
ou +
ou os colocaria em um diretório cujo nome começa com -
ou +
.execvp()
/ / execlp()
-type. E, nesse caso, geralmente você os chama, the-script
para que seja procurado; $PATH
nesse caso, o argumento do caminho para a execve()
chamada do sistema geralmente começa com /
(não -
nem +
) ou como ./the-script
se você deseja que the-script
o diretório atual seja executado (e então o caminho começa com ./
, -
nem +
nem).Agora, além do problema de correção teórica , há outra razão pela qual #! /bin/sh -
foi recomendada como boa prática . E isso remonta a uma época em que vários sistemas ainda suportavam scripts setuid.
Se você possui um script que contém:
#! /bin/sh
/bin/echo "I'm running as root"
E esse script foi definido como root (como com -r-sr-xr-x root bin
permissões), nesses sistemas, quando executado por um usuário comum, o
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
seria feito como root
!
Se o usuário criou um link simbólico /tmp/-i -> path/to/the-script
e o executou como -i
, ele iniciaria um shell interativo ( /bin/sh -i
) como root
.
O -
iria trabalhar em torno disso (que não iria funcionar em torno da questão racial-condição , ou o fato de que algumas sh
implementações como alguns ksh88
queridos baseados iria pesquisar argumentos de script, sem /
no $PATH
entanto).
Atualmente, quase nenhum sistema suporta script setuid por mais tempo, e alguns dos que ainda o fazem (geralmente não o padrão) acabam executando um execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])
(onde <n>
existe um descritor de arquivo aberto para leitura no script) que funciona em torno desse problema e do condição de corrida.
Observe que você obtém problemas semelhantes com a maioria dos intérpretes, não apenas com os cascos Bourne. Os shells não semelhantes a Bourne geralmente não suportam -
como marcador de final de opção, mas geralmente suportam --
(pelo menos para versões modernas).
Além disso
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Não tenha o problema, pois o próximo argumento é considerado como um argumento para a -f
opção em qualquer caso, mas ainda não funcionará se path/to/script
estiver -
(nesse caso, com a maioria das sed
/ awk
implementações, sed
/ awk
não leia o código no -
arquivo, mas do stdin).
Observe também que na maioria dos sistemas, não se pode usar:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Como na maioria dos sistemas, o mecanismo shebang permite apenas um argumento após o caminho do intérprete.
Quanto ao uso de #! /bin/sh -
vs #!/bin/sh -
, isso é apenas uma questão de gosto. Prefiro o primeiro, pois torna o caminho do intérprete mais visível e facilita a seleção do mouse. Há uma lenda que diz que o espaço era necessário em algumas versões antigas do Unix, exceto o AFAIK, que nunca foi verificado.
Uma referência muito boa sobre o shebang do Unix pode ser encontrada em https://www.in-ulm.de/~mascheck/various/shebang
bash
aceita opções como qualquer outro shell. Sendo um shell Bourix e POSIX,bash
aceita ambos#! /bin/bash -
e#! /bin/bash --
.