GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Platzieren Klammern den Befehl wirklich in einer Subshell?

Nach dem, was ich gelesen habe, sollte ein Befehl in Klammern in einer Subshell ausgeführt werden, ähnlich wie beim Ausführen eines Skripts. Wenn dies wahr ist, wie sieht es die Variable x, wenn x nicht exportiert wird?

x=1

Ausführen von (echo $x) auf der Kommandozeile ergibt 1

Ausführen von echo $x in einem Skript ergibt erwartungsgemäß nichts

Akzeptierte Antwort:

Eine Subshell beginnt als fast identische Kopie des ursprünglichen Shell-Prozesses. Unter der Haube ruft die Shell den fork auf Systemaufruf, der einen neuen Prozess erstellt, dessen Code und Speicher Kopien 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 das $$ Die spezielle Variable behält denselben Wert in Subshells bei:Es ist die Prozess-ID der ursprünglichen Shell. Ebenso $PPID ist die PID des Elternteils der Original-Shell.

Ein paar Shells ändern ein paar Variablen in der Subshell. Bash setzt BASHPID an die PID des Shell-Prozesses, die sich in Subshells ändert. Bash, zsh und mksh sorgen für $RANDOM um unterschiedliche Werte in der übergeordneten und in der Subshell zu erhalten. Aber abgesehen von solchen eingebauten Sonderfällen haben alle Variablen in der Subshell denselben Wert wie in der Original-Shell, denselben Exportstatus, denselben Nur-Lese-Status usw. Alle Funktionsdefinitionen, Alias-Definitionen, Shell-Optionen und andere Einstellungen werden ebenfalls vererbt.

Eine von (…) erstellte Subshell hat dieselben Dateideskriptoren wie sein Ersteller. Einige andere Mittel zum Erstellen von Subshells modifizieren einige Dateideskriptoren, bevor Benutzercode ausgeführt wird. Beispielsweise verläuft die linke Seite eines Rohrs in einer Unterschale, wobei der Standardausgang mit dem Rohr verbunden ist. Die Subshell beginnt auch mit demselben aktuellen Verzeichnis, derselben Signalmaske usw. Eine der wenigen Ausnahmen ist, dass Subshells keine benutzerdefinierten Traps erben:ignorierte Signale (trap '' SIGNAL ) werden in der Subshell ignoriert, aber andere Traps (trap CODE SIGNAL ) werden auf die Standardaktion zurückgesetzt.

Eine Subshell unterscheidet sich also von der Ausführung eines Skripts. Ein Skript ist ein separates Programm. Dieses separate Programm könnte zufällig auch ein Skript sein, das von demselben Interpreter wie das Elternprogramm ausgeführt wird, aber diese Koinzidenz gibt dem separaten Programm keine besondere Sichtbarkeit auf interne Daten des Elternprogramms. Nicht exportierte Variablen sind interne Daten, wenn also der Interpreter für das untergeordnete Shell-Skript ausgeführt wird, sieht er diese Variablen nicht. Exportierte Variablen, also Umgebungsvariablen, werden an ausgeführte Programme übermittelt.

Also:

x=1
(echo $x)

gibt 1 aus weil die Subshell eine Replikation der Shell ist, die sie hervorgebracht hat.

x=1
sh -c 'echo $x'

zufällig eine Shell als untergeordneten Prozess einer Shell ausführt, aber x in der zweiten Zeile hat keine Verbindung mehr mit dem x in der zweiten Zeile als in

x=1
perl -le 'print $x'

oder

x=1
python -c 'print x'

Eine Ausnahme ist der ksh93 Shell, in der das Forking optimiert und die meisten seiner Nebenwirkungen emuliert werden.
Semantisch sind sie Kopien. Aus Implementierungssicht wird viel geteilt.
Für die rechte Seite hängt es von der Schale ab.
Wenn Sie das testen, beachten Sie Dinge wie $(trap) kann die Fallen der ursprünglichen Shell melden. Beachten Sie auch, dass viele Granaten Fehler in Eckfällen mit Fallen haben. Beispielsweise 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) )' führt den ERR aus trap aus der verschachtelten Subshell im Fall „zwei Subshells“, aber nicht der ERR trap aus der Zwischen-Subshell — set -E Option sollte den ERR weitergeben trap zu allen Subshells, aber die dazwischen liegende Subshell wird wegoptimiert und ist daher nicht da, um ihren ERR auszuführen fangen.

Siehe auch:Linux – Warum funktioniert setuid nicht?
Linux
  1. Was ist der Unterschied zwischen dem Abrufen der Befehlsausgabe mit "command" und $(command) in der Shell??

  2. Werden Nicht-Umgebungsvariablen an die durch Befehlssubstitution aufgerufene Subshell übergeben?

  3. Anpassen der Bash Shell:Fett/Farbe Der Befehl?

  4. Wie werden Klammern in der Befehlszeile interpretiert?

  5. Verwenden des passwd-Befehls innerhalb eines Shell-Skripts

Quellbefehl unter Linux

Was ist die Shell unter Linux?

Kommando-Shell

Wie weist man die Ausgabe eines Befehls einer Shell-Variablen zu?

Der Sinn des externen Befehls „cd“?

Bash fc-Befehl:Verwenden Sie die Bash-Shell ganz einfach wie ein Profi