Le manuel de Bash dit :
La substitution de commandes, les commandes regroupées entre parenthèses et les commandes asynchrones sont appelées dans un environnement de sous-shell qui est un doublon de l'environnement du shell,
sauf que les interruptions interceptées par le shell sont réinitialisées aux valeurs que le shell a héritées de son parent à appel.
Dans cet exemple, b
n'est pas une variable d'environnement, donc b
n'existe pas dans le sous-shell créé par la substitution de commande. Alors pourquoi est c
attribué la valeur de b
par substitution de commande ? Est-ce parce que l'expansion des paramètres se produit pour $b
dans le processus shell avant de créer un sous-shell pour exécuter echo 1
?
$ b=1
$ c=$(echo $b)
$ echo $c
1
Réponse acceptée :
Non, le sous-shell a été créé en premier.
Un environnement d'exécution de shell contient des paramètres de shell définis par des affectations de variables et des variables d'environnement. Un environnement de sous-shell a été créé en dupliquant l'environnement shell, il contient donc toutes les variables de l'environnement shell actuel.
Voir l'exemple :
$ b=1
$ c=$(b=2; echo "$b")
$ echo "$c"
2
La sortie est 2
au lieu de 1
.
Un environnement de sous-shell créé par substitution de commande est différent d'un environnement de shell créé en appelant l'exécutable du shell.
Lorsque vous appelez le shell en tant que :
$ bash -c :
le shell actuel a utilisé execve() pour créer un nouveau processus shell, quelque chose comme :
execve("/bin/bash", ["bash", "-c", ":"], [/* 64 vars */]) = 0
le dernier argument passé à execve
contient toutes les variables d'environnement.
C'est pourquoi vous devez exporter les variables pour les pousser vers les variables d'environnement, qui seront incluses dans les commandes exécutées ultérieurement :
$ a=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++
Notez que les variables d'environnement passent de 64 à 65. Et les variables qui ne sont pas exportées ne seront pas transmises au nouvel environnement shell :
$ a=; b=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++
Notez que les variables d'environnement sont toujours 65.
Dans la substitution de commande, le shell a utilisé fork() pour créer un nouveau processus shell, qui vient de copier l'environnement shell actuel - qui contient à la fois l'ensemble de variables et les variables d'environnement.