Eine Subshell beginnt als nahezu identische Kopie des ursprünglichen Shell-Prozesses. Unter der Haube ruft die Shell den fork
Systemaufruf 1 auf , der einen neuen Prozess erstellt, dessen Code und Speicher Kopien 2 sind . Wenn die Subshell erstellt wird, gibt es nur sehr wenige Unterschiede zwischen ihr und ihrem übergeordneten Element. Insbesondere haben sie die gleichen Variablen. Sogar die $$
Spezialvariable behält in Subshells den gleichen Wert: Es ist die Prozess-ID der Original-Shell. Ebenso $PPID
ist die PID des übergeordneten Elements der ursprünglichen Shell.
Einige Shells ändern einige Variablen in der Subshell. Bash setzt BASHPID
auf die PID des Shell-Prozesses, die sich in Subshells ändert. Bash, zsh und mksh sorgen dafür $RANDOM
, dass im Parent und in der Subshell unterschiedliche Werte ausgegeben werden. Abgesehen von solchen Sonderfällen haben alle Variablen in der Subshell denselben Wert wie in der ursprünglichen Shell, denselben Exportstatus, denselben Nur-Lese-Status usw. Alle Funktionsdefinitionen, Aliasdefinitionen, Shell-Optionen und andere Einstellungen werden ebenfalls übernommen.
Eine von erstellte Subshell (…)
hat dieselben Dateideskriptoren wie ihr Ersteller. Einige andere Methoden zum Erstellen von Subshells ändern einige Dateideskriptoren, bevor Benutzercode ausgeführt wird. Beispielsweise verläuft die linke Seite einer Rohrleitung in einer Unterschale 3, deren Standardausgang mit der Rohrleitung verbunden ist. Die Subshell startet auch mit demselben aktuellen Verzeichnis, derselben Signalmaske usw. Eine der wenigen Ausnahmen ist, dass Subshells keine benutzerdefinierten Traps erben: Ignorierte Signale ( ) bleiben in der Subshell ignoriert, andere Traps ( SIGNAL ) werden jedoch zurückgesetzt zur Standardaktion 4 .trap '' SIGNAL
trap CODE
Eine Subshell unterscheidet sich somit von der Ausführung eines Skripts. Ein Skript ist ein separates Programm. Dieses separate Programm kann zufällig auch ein Skript sein, das vom selben Interpreter wie das übergeordnete Programm ausgeführt wird, aber dieses Zusammentreffen verleiht dem separaten Programm keine besondere Sichtbarkeit für interne Daten des übergeordneten Programms. Nicht exportierte Variablen sind interne Daten. Wenn der Interpreter für das untergeordnete Shell-Skript ausgeführt wird , werden diese Variablen nicht angezeigt. Exportierte Variablen, dh Umgebungsvariablen, werden an ausgeführte Programme übertragen.
Somit:
x=1
(echo $x)
wird gedruckt, 1
weil die Subshell eine Replikation der Shell ist, die sie erzeugt hat.
x=1
sh -c 'echo $x'
zufällig wird eine Shell als untergeordneter Prozess einer Shell ausgeführt, aber die x
in der zweiten Zeile hat keine größere Verbindung mit der x
in der zweiten Zeile als in
x=1
perl -le 'print $x'
oder
x=1
python -c 'print x'
1 Eine Ausnahme bildet die ksh93
Schale, in der das Gabeln optimiert und die meisten Nebenwirkungen emuliert werden.
2 Semantisch handelt es sich um Kopien. Aus Sicht der Implementierung wird viel geteilt.
3 Für die rechte Seite kommt es auf die Schale an.
4 Wenn Sie dies testen, beachten Sie, dass Dinge wie$(trap)
die Fallen der ursprünglichen Shell melden können. Beachten Sie auch, dass viele Muscheln in Eckfällen mit Fallen Fehler aufweisen. Zum Beispiel stellt Ninjalj fest, dass ab 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) )'
die ERR
Trap von der verschachtelten Subshell in dem Fall "Zwei Subshells" ausgeführt wird, aber nicht die ERR
Trap von der Zwischen-Subshell - set -E
Option sollte die Propagierung durchführenERR
Trap auf alle Subshells, aber die Zwischen-Subshell ist optimiert und daher nicht dazu da, den ERR
Trap auszuführen .
x=out; (x=in; echo $x)
)echo $(x=2; echo $x)
das Fragment$(x=2; echo $x)
erweitert werden. Dies erfordert die Auswertung des Befehlsx=2; echo $x
. Die Erweiterung von$x
geschieht während dieser Auswertung, nachdem das Teil ausgewertet wurdex=2
.x
ungesetzt)echo $(echo foo >somefile)${x-$(cat somefile)}
oderecho $(echo $x),${x=1}
../file
wird nicht in einer Subshell ausgeführt. Siehe auch unix.stackexchange.com/q/261638 und unix.stackexchange.com/a/157962Ja, natürlich wird, wie in der gesamten Dokumentation angegeben, ein Befehl in Klammern in einer Subshell ausgeführt.
Die Subshell erbt eine Kopie aller übergeordneten Variablen. Der Unterschied besteht darin, dass alle Änderungen, die Sie in der Subshell vornehmen, nicht auch in der übergeordneten Shell vorgenommen werden.
Die ksh-Manpage macht dies etwas klarer als die bash-Manpage:
man ksh
:man bash
:quelle
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.
dem Punkt:· shell variables and functions marked for export, along with variables exported for the command, passed in the environment
(aus demselbenman bash
Abschnitt), der erklärt, warum einecho $x
-script nichts druckt, wennx
es nicht exportiert wird.