Le Learning Bash Book mentionne qu'un sous-shell n'héritera que des variables d'environnement et des descripteurs de fichiers, etc., et qu'il n'héritera pas des variables qui ne sont pas exportées :
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
Comme je le sais, le shell créera deux sous-shells pour ()
et pour ./file
, mais pourquoi dans le ()
cas le sous-shell identifie-t-il le var
variable bien qu'elle ne soit pas exportée et dans le ./file
au cas où il ne l'aurait pas identifié ?
# Strace for ()
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631
J'ai essayé d'utiliser strace
pour comprendre comment cela se produit et, étonnamment, j'ai découvert que bash utiliserait les mêmes arguments pour l'appel système clone, ce qui signifie que le processus fourchu dans ()
et ./file
devrait avoir le même espace d'adressage de processus que le parent, alors pourquoi dans le ()
case est la variable visible par le sous-shell et il n'en va pas de même pour le ./file
cas, bien que les mêmes arguments soient basés sur l'appel système clone ?
Réponse acceptée :
Le Learning Bash Book est faux. Les sous-interpréteurs héritent de toutes les variables. Même $$
(le PID du shell d'origine) est conservé. La raison en est que pour un sous-shell, le shell se contente de bifurquer et n'exécute pas un nouveau shell (au contraire, lorsque vous tapez ./file
, une nouvelle commande est exécutée, par ex. une nouvelle coquille; dans la sortie strace, regardez execve
et similaires). Donc, fondamentalement, ce n'est qu'une copie (avec quelques différences documentées).
Remarque :ceci n'est pas spécifique à bash; ceci est vrai pour n'importe quel shell.