Un sous-shell commence par être une copie presque identique du processus shell original. Sous le capot, le shell appelle l' forkappel système 1 qui crée un nouveau processus dont le code et la mémoire sont des copies 2 . Lorsque le sous-shell est créé, il existe très peu de différences entre celui-ci et son parent. En particulier, ils ont les mêmes variables. Même la $$variable spéciale conserve la même valeur dans les sous-shell: il s'agit de l'ID de processus du shell d'origine. De même $PPIDest le PID du parent du shell d'origine.
Quelques coquilles changent quelques variables dans le sous-coquille. Bash définit BASHPIDle PID du processus shell, qui change de sous-shell. Bash, zsh et mksh font en sorte $RANDOMde générer différentes valeurs dans le parent et dans le sous-shell. Mais à part les cas spéciaux intégrés tels que ceux-ci, toutes les variables ont la même valeur dans le sous-shell que dans le shell d'origine, le même statut d'exportation, le même statut en lecture seule, etc. Toutes les définitions de fonctions, définitions d'alias, options de shell et les autres paramètres sont également hérités.
Un sous-shell créé par (…)a les mêmes descripteurs de fichier que son créateur. Certains autres moyens de créer des sous-shell modifient certains descripteurs de fichier avant l'exécution du code utilisateur; Par exemple, le côté gauche d'un tuyau se trouve dans un sous-shell 3 avec une sortie standard connectée au tuyau. Le sous-shell commence également avec le même répertoire actuel, le même masque de signal, etc. Une des rares exceptions est que les sous-shell n'héritent pas des traps personnalisés: les signaux ignorés ( ) restent ignorés dans le sous-shell, mais les autres traps ( SIGNAL ) sont réinitialisés. à l'action par défaut 4 .trap '' SIGNALtrap CODE
Un sous-shell est donc différent de l'exécution d'un script. Un script est un programme séparé. Ce programme séparé peut également être un script exécuté par le même interprète que le parent, mais cette coïncidence ne confère au programme séparé aucune visibilité particulière sur les données internes du parent. Les variables non exportées sont des données internes. Ainsi, lorsque l'interpréteur du script de shell enfant est exécuté , il ne voit pas ces variables. Les variables exportées, c'est-à-dire les variables d'environnement, sont transmises aux programmes exécutés.
Ainsi:
x=1
(echo $x)
imprime 1parce que le sous-shell est une réplication du shell qui l’a engendré.
x=1
sh -c 'echo $x'
arrive à exécuter un shell en tant que processus enfant d'un shell, mais xla seconde ligne n'a pas plus de connexion avec xla seconde ligne que dans
x=1
perl -le 'print $x'
ou
x=1
python -c 'print x'
1 Une exception est le ksh93shell où le forgeage est optimisé et où la plupart de ses effets secondaires sont imités.
2 Sémantiquement, ce sont des copies. Du point de vue de la mise en œuvre, il y a beaucoup de partage.
3 Pour le côté droit, cela dépend de la coque.
4 Si vous testez cela, notez que des choses similaires$(trap) peuvent signaler les pièges du shell original. Notez également que beaucoup de coquilles ont des bugs dans les cas de coin impliquant des pièges. Par exemple, ninjalj note que depuis bash 4.3, bash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'exécute le ERRpiège à partir du sous-shell imbriqué dans le cas «deux sous-réservoirs», mais pas le ERRpiège du sous-shell intermédiaire - l' set -Eoption devrait propager leERRpiège à tous les sous-shell, mais le sous-shell intermédiaire est optimisé et n’est donc pas là pour exécuter son ERRpiège.
x=out; (x=in; echo $x))