Un sous-shell commence par être une copie presque identique du processus shell original. Sous le capot, le shell appelle l' fork
appel 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 $PPID
est le PID du parent du shell d'origine.
Quelques coquilles changent quelques variables dans le sous-coquille. Bash définit BASHPID
le PID du processus shell, qui change de sous-shell. Bash, zsh et mksh font en sorte $RANDOM
de 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 '' SIGNAL
trap 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 1
parce 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 x
la seconde ligne n'a pas plus de connexion avec x
la seconde ligne que dans
x=1
perl -le 'print $x'
ou
x=1
python -c 'print x'
1 Une exception est le ksh93
shell 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 ERR
piège à partir du sous-shell imbriqué dans le cas «deux sous-réservoirs», mais pas le ERR
piège du sous-shell intermédiaire - l' set -E
option devrait propager leERR
piège à tous les sous-shell, mais le sous-shell intermédiaire est optimisé et n’est donc pas là pour exécuter son ERR
piège.
x=out; (x=in; echo $x)
)echo $(x=2; echo $x)
, le fragment$(x=2; echo $x)
doit être développé. Cela nécessite d'évaluer la commandex=2; echo $x
. L'expansion de$x
se produit pendant cette évaluation, après avoir évalué la piècex=2
.x
non défini)echo $(echo foo >somefile)${x-$(cat somefile)}
ouecho $(echo $x),${x=1}
../file
n'est pas exécuté dans un sous-shell. Voir aussi unix.stackexchange.com/q/261638 et unix.stackexchange.com/a/157962Évidemment, comme le dit toute la documentation, une commande entre parenthèses est exécutée dans un sous-shell.
Le sous-shell hérite d'une copie de toutes les variables du parent. La différence est que les modifications que vous apportez dans le sous-shell ne sont pas également effectuées dans le parent.
La page de manuel ksh le rend un peu plus clair que celui de bash:
man ksh
:man bash
:la source
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following.
, qui contient l'élément:· shell variables and functions marked for export, along with variables exported for the command, passed in the environment
(de la mêmeman bash
section) ce qui explique pourquoi unecho $x
script n'imprime rien s'ilx
n'est pas exporté.