Das Learning Bash Book erwähnt, dass eine Subshell nur Umgebungsvariablen und Dateideskriptoren usw. erben wird und dass sie keine Variablen erben wird, die nicht exportiert werden:
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
Wie ich weiß, erstellt die Shell zwei Subshells für ()
und für ./file
, aber warum im ()
Fall identifiziert die Subshell die var
Variable, obwohl sie nicht exportiert wird und in der ./file
falls es es nicht identifiziert hat?
# 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
Ich habe versucht, strace
zu verwenden um herauszufinden, wie das passiert, und überraschenderweise fand ich heraus, dass bash dieselben Argumente für den Klon-Systemaufruf verwendet, was bedeutet, dass sowohl der gegabelte Prozess in ()
und ./file
sollte denselben Prozessadressraum wie der Elternprozess haben, also warum in ()
case ist die Variable, die für die Subshell sichtbar ist, und dasselbe gilt nicht für ./file
Fall, obwohl dieselben Argumente auf dem Clone-Systemaufruf basieren?
Akzeptierte Antwort:
Das Learning Bash Book ist falsch. Subshells erben alle Variablen. Sogar $$
(die PID der ursprünglichen Shell) wird beibehalten. Der Grund dafür ist, dass sich die Shell bei einer Subshell nur verzweigt und keine neue Shell ausführt (im Gegenteil, wenn Sie ./file
eingeben , wird ein neuer Befehl ausgeführt, z. eine neue Hülle; Sehen Sie sich in der Strace-Ausgabe execve
an und ähnliches). Im Grunde ist es also nur eine Kopie (mit einigen dokumentierten Unterschieden).
Hinweis:Dies ist nicht spezifisch für Bash; das gilt für jede Shell.