Pendant que je jouais dans mon Shell pour enquêter sur la réponse à cette question , j'ai remarqué que, même si /bin/sh
pointait vers /bin/bash
sur mon système, les deux commandes se comportent différemment. Tout d'abord, la sortie de
ls -lh /bin/sh
est:
lrwxrwxrwx 1 root root 4 Apr 22 2013 /bin/sh -> bash*
Cependant, l'appel de la commande suivante via /bin/sh
:
/bin/sh -c "script.sh 2> >( grep -v FILTER 2>&1 )"
renvoie cette erreur:
/bin/sh: -c: line 0: syntax error near unexpected token '>'
/bin/sh: -c: line 0: 'script.sh 2> >( grep -v FILTER 2>&1 )'
Lors de l'exécution de la même commande via /bin/bash
:
/bin/bash -c "script.sh 2> >( grep -v FILTER 2>&1 )"
s'exécute avec succès, voici la sortie:
This should be on stderr
Pour référence, voici le contenu de script.sh
:
#!/bin/sh
echo "FILTER: This should be filtered out" 1>&2
echo "This should be on stderr" 1>&2
echo "FILTER: This should be filtered out" 1>&2
Pourquoi les deux invocations se comportent-elles différemment?
bash
examine la valeur de $argv[0]
(bash est implémenté en C) pour déterminer comment il a été appelé.
Son comportement lorsqu'il est appelé en tant que sh
est documenté dans le manuel :
Si Bash est appelé avec le nom
sh
, il essaie d'imiter le comportement de démarrage des versions historiques desh
aussi fidèlement que possible, tout en se conformant également à la norme POSIX.Lorsqu'il est invoqué en tant que shell de connexion interactif ou en tant que shell non interactif avec l'option
-login
, Il tente d'abord de lire et d'exécuter des commandes à partir de/etc/profile
Et~/.profile
, Dans ce commande. L'option--noprofile
Peut être utilisée pour inhiber ce comportement. Lorsqu'elle est invoquée en tant que Shell interactif avec le nomsh
, Bash recherche la variableENV
, étend sa valeur si elle est définie et utilise la valeur développée comme nom d'un fichier à lire et exécuter. Puisqu'un shell appelé commesh
n'essaye pas de lire et d'exécuter des commandes à partir d'autres fichiers de démarrage, l'option--rcfile
N'a aucun effet. Un shell non interactif appelé avec le nomsh
n'essaie pas de lire d'autres fichiers de démarrage.Lorsqu'il est appelé en tant que
sh
, Bash passe en mode POSIX après la lecture des fichiers de démarrage
Il y a une longue liste (actuellement 46 éléments) de choses qui changent lorsque bash
est en mode POSIX, documenté ici .
(Le mode POSIX est probablement surtout utile pour tester la portabilité des scripts vers des shells nonbash
.)
Soit dit en passant, les programmes qui modifient leur comportement en fonction du nom sous lequel ils ont été appelés sont assez courants. Certaines versions de grep
, fgrep
et egrep
sont implémentées comme un seul exécutable (bien que GNU grep
doesn ' view
est généralement un lien symbolique vers vi
ou vim
; l'invoquer comme view
provoque son ouverture en mode lecture seule. Busybox système comprend un certain nombre de commandes individuelles qui sont toutes des liens symboliques vers l'exécutable maître busybox
.
L'appel de bash en tant que sh
le fait passer en mode posix après avoir lu les fichiers de démarrage qu'il lirait normalement (par opposition aux fichiers de démarrage un POSIX sh se lirait.) Bash a de nombreux modes d'invocation différents. Vous pouvez découvrir ces modes dans la section INVOCATION
du manuel. Voici quelques détails sur le mode POSIX.
Ce mode signifie que bash essaiera, à divers degrés, de se conformer aux attentes POSIX. Comme expliqué ici , bash a quelques invocations différentes pour ce mode, avec des implications légèrement différentes:
sh
: Bash passe en mode POSIX après avoir lu les fichiers de démarrage.bash --posix
: Bash passe en mode POSIX avant de lire les fichiers de démarrage.set -o posix
: Bash passe en mode POSIX.POSIXLY_CORRECT
: Si cette variable se trouve dans l'environnement au démarrage de bash, le shell passe en mode posix avant de lire les fichiers de démarrage, comme bash --posix
. S'il est défini pendant que bash est en cours d'exécution, comme set -o posix
.Dans le Manuel de référence Bash :
Si Bash est appelé avec le nom sh, il essaie d'imiter le comportement de démarrage des versions historiques de sh aussi fidèlement que possible, tout en se conformant également à la norme POSIX.
Parce que le binaire bash
vérifie comment il a été appelé (via argv[0]
) et passe en mode de compatibilité s'il est exécuté en tant que sh
.