web-dev-qa-db-fra.com

Pourquoi / bin / sh se comporte-t-il différemment de / bin / bash même si l'un pointe vers l'autre?

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?

64
Squirrel

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 de sh 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 nom sh, Bash recherche la variable ENV, é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é comme sh 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 nom sh 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.

79
Keith Thompson

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.

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:

  1. sh: Bash passe en mode POSIX après avoir lu les fichiers de démarrage.
  2. bash --posix: Bash passe en mode POSIX avant de lire les fichiers de démarrage.
  3. set -o posix: Bash passe en mode POSIX.
  4. 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.
20
kojiro

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.

16
Etan Reisner

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.

10
Carl Norum