#! / bin / sh -
Est (ou du moins était) souvent le shebang recommandé pour interpréter un script /bin/sh
.
Pourquoi pas juste #! /bin/sh
ou #!/bin/sh
?
À quoi ça -
sert?
#! / bin / sh -
Est (ou du moins était) souvent le shebang recommandé pour interpréter un script /bin/sh
.
Pourquoi pas juste #! /bin/sh
ou #!/bin/sh
?
À quoi ça -
sert?
Réponses:
C'est pour une raison similaire à la raison pour laquelle vous devez écrire:
rm -- *.txt
Et pas
rm *.txt
Sauf si vous pouvez garantir qu'aucun des .txt
fichiers du répertoire actuel ne porte un nom commençant par -
.
Dans:
rm <arg>
<arg>
est considéré comme une option s'il commence par -
ou un fichier à supprimer dans le cas contraire. Dans
rm - <arg>
arg
est toujours considéré comme un fichier à supprimer, qu'il démarre -
ou non.
C'est pareil pour sh
.
Quand on exécute un script qui commence par
#! /bin/sh
Généralement avec:
execve("path/to/the-script", ["the-script", "arg"], [environ])
Le système le transforme en:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
Ce path/to/the-script
n'est généralement pas quelque chose qui est sous le contrôle de l'auteur du script. L'auteur ne peut pas prédire où les copies du script seront stockées ni sous quel nom. En particulier, ils ne peuvent pas garantir que le nom path/to/the-script
avec lequel il est appelé ne commencera pas -
(ou +
qui est également un problème avec sh
). C'est pourquoi nous avons besoin de l' -
ici pour marquer la fin des options.
Par exemple, sur mon système zcat
(comme la plupart des autres scripts en fait) est un exemple de script qui n'a pas suivi cette recommandation:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Vous pouvez maintenant demander pourquoi #! /bin/sh -
et non #! /bin/sh --
?
Alors #! /bin/sh --
qu'il fonctionnerait avec des shells POSIX, le #! /bin/sh -
est plus portable; en particulier aux anciennes versions de sh
. sh
le traitement des prédates -
de fin d'option et de fin d'option getopt()
et l'utilisation générale de --
pour marquer la fin des options de longue date. La façon dont le shell Bourne (à partir de la fin des années 70) a analysé ses arguments, seul le premier argument était considéré pour les options s'il commençait par -
. Tous les caractères suivants -
seraient traités comme des noms d'options; s'il n'y avait pas de caractère après le -
, il n'y avait pas d'options. Cela a bloqué et tous les obus similaires à Bourne plus tard reconnaissent -
comme un moyen de marquer la fin des options.
Dans le shell Bourne (mais pas dans les shells modernes de type Bourne), #! /bin/sh -euf
contournerait également le problème car seul le premier argument était considéré pour les options.
Maintenant, on pourrait dire que nous sommes pédants ici, et c'est aussi pourquoi j'ai écrit le besoin en italique ci-dessus:
-
ou +
ou les place dans un répertoire dont le nom commence par -
ou +
.execvp()
/ execlp()
. Et dans ce cas, vous les invoquez généralement soit the-script
pour qu'il soit recherché, $PATH
auquel cas l'argument de chemin d'accès à l' execve()
appel système commence généralement par /
(pas -
ni +
), soit comme ./the-script
si vous vouliez que the-script
le répertoire courant soit exécuté (et alors le chemin commence par ./
, pas -
non +
plus).Maintenant, à côté de la question de l' exactitude théorique , il y a une autre raison pour laquelle elle a #! /bin/sh -
été recommandée comme bonne pratique . Et cela remonte à une époque où plusieurs systèmes prenaient encore en charge les scripts setuid.
Si vous avez un script qui contient:
#! /bin/sh
/bin/echo "I'm running as root"
Et ce script était root setuid (comme avec les -r-sr-xr-x root bin
autorisations), sur ces systèmes, lorsqu'il est exécuté par un utilisateur ordinaire, le
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
se ferait comme root
!
Si l'utilisateur créait un lien symbolique /tmp/-i -> path/to/the-script
et l'exécutait en tant que -i
, il lancerait un shell interactif ( /bin/sh -i
) en tant que root
.
Le -
travaillerait autour de cette (cela ne fonctionnerait pas autour de la question condition de course , ou le fait que certaines sh
mises en œuvre comme certains ksh88
les auraient à base de script rechercher des arguments sans /
en $PATH
bien).
De nos jours, pratiquement aucun système ne prend plus en charge le script setuid, et certains de ceux qui le font encore (généralement pas par défaut), finissent par faire un execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])
(où <n>
est un descripteur de fichier ouvert pour la lecture sur le script) qui contourne à la fois ce problème et le condition de course.
Notez que vous rencontrez des problèmes similaires avec la plupart des interprètes, pas seulement les shells de type Bourne. Les shells non Bourne-like ne prennent généralement pas en charge -
comme marqueur de fin d'option, mais prennent généralement en charge à la --
place (au moins pour les versions modernes).
Également
#! /usr/bin/awk -f
#! /usr/bin/sed -f
N'ayez pas le problème car l'argument suivant est considéré comme un argument de l' -f
option dans tous les cas, mais cela ne fonctionne toujours pas si path/to/script
est -
(dans ce cas, avec la plupart des sed
/ awk
implémentations, sed
/ awk
ne lit pas le code de la -
fichier, mais à partir de stdin à la place).
Notez également que sur la plupart des systèmes, on ne peut pas utiliser:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Comme sur la plupart des systèmes, le mécanisme shebang n'autorise qu'un seul argument après le chemin de l'interpréteur.
Quant à savoir si utiliser #! /bin/sh -
vs #!/bin/sh -
, c'est juste une question de goût. Je préfère le premier car il rend le chemin de l'interpréteur plus visible et facilite la sélection de la souris. Il y a une légende qui dit que l'espace était nécessaire dans certaines anciennes versions d'Unix mais AFAIK, qui n'a jamais été vérifié.
Une très bonne référence sur le shebang Unix peut être trouvée sur https://www.in-ulm.de/~mascheck/various/shebang
bash
accepte des options comme tout autre shell. Étant un shell Bourne-like et POSIX, bash
accepte les deux #! /bin/bash -
et #! /bin/bash --
.