Ist $ () eine Subshell?

51

Ich verstehe die Subshell-Syntax als (<commands...>), ist $()nur eine Subshell, von der Sie Variablenwerte abrufen können?

Hinweis: Dies gilt für Bash 4.4 basierend auf unterschiedlichen Formulierungen in der Dokumentation.

leeand00
quelle
4
Mögliches Duplikat von Was ist eine Befehlsersetzung in einer Shell?
Julien Lopez

Antworten:

75

$(…)ist per definitionem eine Subshell: Sie ist eine Kopie des Shell-Laufzeitstatus¹, und Änderungen am Status der Subshell haben keine Auswirkungen auf den übergeordneten Status. Eine Unterschale wird normalerweise durch Verzweigen eines neuen Prozesses implementiert (einige Schalen können dies jedoch in einigen Fällen optimieren).

Es ist keine Subshell, von der Sie Variablenwerte abrufen können. Wenn sich Änderungen an Variablen auf das übergeordnete Element auswirken würden, wäre dies keine Unterschale. Es ist eine Subshell, deren Ausgabe das übergeordnete Element abrufen kann. Bei der von erstellten Subshell $(…)ist die Standardausgabe auf eine Pipe festgelegt, und das übergeordnete Element liest aus dieser Pipe und sammelt die Ausgabe.

Es gibt mehrere andere Konstrukte, die eine Subshell erstellen. Ich denke, dies ist die vollständige Liste für Bash:

  • Subshell zum Gruppieren : Es ( … )wird nur eine Subshell erstellt und darauf gewartet, dass diese beendet wird. Kontrastieren Sie, mit { … }welchen Gruppenbefehlen nur zu syntaktischen Zwecken und keine Subshell erstellt wird.
  • Hintergrund : … &Erstellt eine Subshell und wartet nicht darauf, dass sie beendet wird.
  • Pipeline : … | …Erstellt zwei Unterschalen, eine für die linke und eine für die rechte Seite, und wartet, bis beide beendet sind. Die Shell erstellt eine Pipe und verbindet die Standardausgabe der linken Seite mit dem Schreibende der Pipe und die Standardeingabe der rechten Seite mit dem Leseende. In einigen Shells (ksh88, ksh93, zsh, bash mit aktivierter lastpipeOption ) wird die rechte Seite in der ursprünglichen Shell ausgeführt, sodass das Pipeline-Konstrukt nur eine Subshell erstellt.
  • Befehl Substitution : $(…)(auch Dinkel `…`) erzeugt eine Subshell mit seinem Standardausgabesatz an ein Rohr, speichert die Ausgabe in der Eltern- und expandiert in diesem Ausgang, abzüglich sein nachlauf newlines. (Und die Ausgabe kann weiter gespalten und verschoben werden, aber das ist eine andere Geschichte.)
  • Prozessersetzung : <(…)Erstellt eine Subshell, deren Standardausgabe auf eine Pipe festgelegt ist, und erweitert sie auf den Namen der Pipe. Das übergeordnete Element (oder ein anderer Prozess) kann die Pipe öffnen, um mit der Subshell zu kommunizieren. >(…)tut dasselbe aber mit der Pipe auf Standardeingabe.
  • Coprozess : coproc …Erstellt eine Subshell und wartet nicht darauf, dass sie beendet wird. Die Standardeingabe und die Standardausgabe der Subshell werden jeweils auf eine Pipe festgelegt, wobei die übergeordnete Pipe mit dem anderen Ende jeder Pipe verbunden ist.

¹ Im Gegensatz zum Ausführen einer separaten Shell .

Gilles 'SO - hör auf böse zu sein'
quelle
Könnten Sie auch ${...}in die Antwort aufnehmen?
user1717828
3
@ user1717828 Was? Warum? Was hat die variable Erweiterung aus der Ferne mit dieser Frage zu tun? Ich werde nicht das gesamte Shell-Handbuch in meine Antwort aufnehmen.
Gilles 'SO- hör auf böse zu sein'
1
Was hat die variable Erweiterung aus der Ferne mit dieser Frage zu tun? Ich weiß nicht, deswegen habe ich gefragt :-) Also denke ich, dass die Ersetzung der geschweiften Klammer nichts mit der Ersetzung der Klammer in Klammern zu tun hat.
user1717828
@ user1717828: Variablenerweiterung hat nichts mit Subshells zu tun. Es ist ein separater Mechanismus und definitiv eine Lektüre wert, wenn Sie gerade erst anfangen!
0xdd
1
@EnricoMariaDeAngelis Es ist nicht der einzige Weg, aber es ist der natürlichste Weg. Eine andere Möglichkeit ist command | { read line; … }(abhängig von der Shell, die linemöglicherweise nach der Pipeline noch verfügbar ist oder nicht). Alle Möglichkeiten beziehen eine Subshell mit ein, da der Befehl, der die Ausgabe erzeugt, unabhängig von der Shell ausgeführt werden muss, die die Eingabe liest. Wenn sich der Befehl ausschließlich innerhalb der Shell befindet (nur Shellkonstruktionen und integrierte Befehle, keine externen Befehle), erstellt die Shell möglicherweise keinen Unterprozess, dies ist jedoch nur eine Optimierung. Es wird dennoch eine Unter-Shell erstellt.
Gilles 'SO - hör auf böse zu sein'
20

Aus der bash (1) -Manpage in der bash-Version 4.4, Abschnitt "EXPANSION", Unterabschnitt "Command Substitution":

Bash führt die Erweiterung durch Ausführung commandin einer Subshell-Umgebung durch [...]

Ignacio Vazquez-Abrams
quelle
9
Dies wird auch von POSIX explizit festgelegt .
Stephen Kitt
1
Interessanterweise erwähnt die bashManpage unter CentOS 7 keine Subshell: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.Ich frage mich, ob dies eine bewusste Unterlassung war.
dr01
6
@ dr01 Im Gegenteil, Bash 4.4 hat den Wortlaut dieses Satzes dahingehend geändert, dass er das Wort "Subshell" enthält. Es war eine Klarstellung: Das Handbuch erwähnte ausdrücklich, dass verschiedene andere Konstrukte Unterschalen waren, aber bis 4.4 wurde es nicht ausdrücklich für die Befehlsersetzung angegeben.
Gilles 'SO- hör auf böse zu sein'
Ja, unter CentOS v7.4.1708 (ziemlich neu) ist bash v4.2.46.
dr01
5

Ja, ( commands... )ist eine bashSubshell, die commands...in einem anderen Prozess ausgeführt wird.

Der einzige Unterschied $( commands... )ist, dass dieser Teil des Codes nach der Ausführung commands...durch alles ersetzt wird, was commands...geschrieben wurde stdout.

Iskustvo
quelle