Was ist der genaue Unterschied zwischen einer „Unterschale“ und einem „untergeordneten Prozess“?

16

Nach diesem und dies wird ein Sub - Shell mithilfe von Klammern gestartet (…).

( echo "Hello" )

Nach dieser , dies und dies ist ein Prozess gegabelt ist , wenn der Befehl mit einem gestartet&

echo "Hello" &

Die Posix-Spezifikation verwendet das Wort subshellauf dieser Seite , definiert es jedoch nicht und definiert auf derselben Seite auch nicht den "untergeordneten Prozess" .

Beide verwenden die Kernelfunktion fork(), richtig?

Was ist der genaue Unterschied, wenn man einige Gabeln als "Sub-Shell" und andere Gabeln als "untergeordneten Prozess" bezeichnet?

Isaac
quelle
Nicht klar , warum Sie eine Verknüpfung POSIX Rationale: Basisdefinitionen anstelle der Basisdefinitionen selbst: 3,93 Child - Prozess „Ein neuer Prozess erstellt (von fork (), posix_spawn (), oder ...) durch einen bestimmten Prozess“ ; 3.376 Subshell "Eine Shell-Ausführungsumgebung, die sich von der Haupt- oder aktuellen Shell-Ausführungsumgebung unterscheidet" . Also keine Instanzen der gleichen Art von Dingen. Ist das die Unterscheidung, die Sie suchen?
Fra-San
@ fra-san A child processkönnte eine andere Umgebung haben als main: Wie in ( LANG=C eval 'echo "$LANG"' ). Ist dieser untergeordnete Prozess (in Klammern) auch eine Unterschale (andere Umgebung)?
Isaac
Der Ausdruck in ( )ist per Definition eine Subshell mit einer eigenen Ausführungsumgebung. Mein Punkt ist, dass eine Subshell nicht als untergeordneter Prozess implementiert werden muss (wie Stéphane in seiner Antwort mit dem Beispiel ksh93 hervorhebt). Es sieht so aus, als müssten Subshell und Child-Prozess nicht beide Ergebnisse eines fork()Aufrufs sein. Daher scheint es mir nicht der richtige Standpunkt zu sein, nach dem Unterschied zwischen zwei Arten von Gabel zu suchen. Deshalb habe ich versucht, Ihre Frage besser zu verstehen.
Fra-San
Ah, jetzt sehe ich , dass die TLDP Seite , die Sie tatsächlich verknüpft sagt , dass ein Sub - Shell ist ein Kind - Prozess. Meiner Meinung nach ist diese Definition eine möglicherweise irreführende Vereinfachung.
Fra-San

Antworten:

15

In der POSIX-Terminologie ist eine Subshell-Umgebung mit dem Begriff der Shell-Ausführungsumgebung verknüpft .

Eine Subshell-Umgebung ist eine separate Shell-Ausführungsumgebung, die als Duplikat der übergeordneten Umgebung erstellt wird. Diese Ausführungsumgebung enthält Dinge wie geöffnete Dateien, Umask, Arbeitsverzeichnis, Shell-Variablen / Funktionen / Aliase ...

Änderungen an dieser Subshell-Umgebung wirken sich nicht auf die übergeordnete Umgebung aus.

Traditionell in der Bourne-Shell oder ksh88, auf der die POSIX-Spezifikation basiert, wurde dies durch Verzweigen eines untergeordneten Prozesses durchgeführt.

Die Bereiche, in denen POSIX die Ausführung von Befehlen in einer Subshell-Umgebung erfordert oder zulässt, sind diejenigen, in denen ksh88 traditionell einen untergeordneten Shell-Prozess gabelte.

Implementierungen werden jedoch nicht gezwungen, dafür einen untergeordneten Prozess zu verwenden.

Eine Shell kann stattdessen wählen, diese separate Ausführungsumgebung nach Belieben zu implementieren.

Zum Beispiel speichert ksh93 die Attribute der übergeordneten Ausführungsumgebung und stellt sie nach Beendigung der Subshell-Umgebung in Kontexten wieder her, in denen das Forking vermieden werden kann (eine Optimierung, da das Forking auf den meisten Systemen recht teuer ist).

Zum Beispiel in:

cd /foo; pwd
(cd /bar; pwd)
pwd

POSIX erfordert die cd /fooAusführung in einer separaten Umgebung und die Ausgabe von:

/foo
/bar
/foo

Es ist nicht erforderlich, dass es in einem separaten Prozess ausgeführt wird. Wenn zum Beispiel stdout zu einer kaputten Pipe wird, kann beim pwdAusführen in der Subshell-Umgebung das SIGPIPE sehr gut an den einzigen Shell-Prozess gesendet werden.

Die meisten Shells einschließlich bashimplementieren es, indem sie den Code (...)in einem untergeordneten Prozess auswerten (während der übergeordnete Prozess auf seine Beendigung wartet), aber ksh93 wird stattdessen beim Ausführen des Codes im (...)selben Prozess alles im selben Prozess ausführen :

  • Denken Sie daran, dass es sich in einer Subshell-Umgebung befindet.
  • auf cd, speichern Sie das vorherige Arbeitsverzeichnis ( in der Regel auf einem Dateideskriptor mit O_CLOEXEC geöffnet), außer dem Wert der OLDPWD, PWD Variablen und alles , was cdändern könnte und dann tut diechdir("/bar")
  • Bei der Rückkehr von der Subshell wird das aktuelle Arbeitsverzeichnis wiederhergestellt (mit einem fchdir()auf dem gespeicherten fd) und alles andere, was die Subshell möglicherweise geändert hat.

Es gibt Kontexte, in denen ein untergeordneter Prozess nicht vermieden werden kann. ksh93 gibt sich nicht ein:

  • var=$(subshell)
  • (subshell)

Aber tut in

  • { subshell; } &
  • { subshell; } | other command

Das heißt, die Fälle, in denen Dinge in separaten Prozessen ausgeführt werden müssen, damit sie gleichzeitig ausgeführt werden können.

ksh93-Optimierungen gehen noch weiter. Zum Beispiel während in

var=$(pwd)

Die meisten Shells würden einen Prozess pwdverzweigen, das untergeordnete Element den Befehl ausführen lassen, dessen Standardausgabe in eine Pipe umgeleitet wird pwd, das aktuelle Arbeitsverzeichnis in diese Pipe schreiben und der übergeordnete Prozess das Ergebnis am anderen Ende der Pipe lesen und ksh93all das von beiden virtualisieren erfordert die Gabel noch das Rohr. Eine Gabel und ein Rohr würden nur für nicht eingebaute Befehle verwendet.

Beachten Sie, dass es andere Kontexte als Unterschalen gibt, für die Schalen einen untergeordneten Prozess verzweigen. Um beispielsweise einen Befehl auszuführen, der in einer separaten ausführbaren Datei gespeichert ist (und der kein Skript für denselben Shell-Interpreter ist), müsste eine Shell einen Prozess verzweigen, um diesen Befehl darin auszuführen, wie dies sonst nicht der Fall wäre Sie können weitere Befehle ausführen, nachdem dieser Befehl zurückgegeben wurde.

Im:

/bin/echo "$((n += 1))"

Dies ist keine Subshell. Der Befehl wird in der aktuellen Shell-Ausführungsumgebung ausgewertet. Die nVariable der aktuellen Shell-Ausführungsumgebung wird inkrementiert. Die Shell gibt jedoch einen untergeordneten Prozess aus, um diesen /bin/echoBefehl mit der Erweiterung $((n += 1))als Argument auszuführen .

Viele Shells implementieren eine Optimierung, indem sie einen untergeordneten Prozess nicht dazu veranlassen, diesen externen Befehl auszuführen, wenn es sich um den letzten Befehl eines Skripts oder einer Unterschale handelt (für die Unterschalen, die als untergeordnete Prozesse implementiert sind). ( bashDies geschieht jedoch nur, wenn dieser Befehl der einzige Befehl der Subshell ist.)

Dies bedeutet, dass bei diesen Shells, wenn der letzte Befehl in der Subshell ein externer Befehl ist, die Subshell keinen zusätzlichen Prozess erzeugt. Wenn Sie vergleichen:

a=1; /bin/echo "$a"; a=2; /bin/echo "$a"

mit

a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")

Es wird die gleiche Anzahl von Prozessen erstellt, nur im zweiten Fall wird die zweite Verzweigung früher ausgeführt, so dass die a=2 Zweig in einer Subshell-Umgebung ausgeführt wird.

Stéphane Chazelas
quelle
1

Unterschale

Die untergeordnete Shell wird auch als Subshell bezeichnet. Die Subshell kann aus der übergeordneten Shell und aus einer anderen Shell erstellt werden. Die Unterschale kann erstellt werden mit:

1. Prozessliste

Eine Prozessliste ist eine in Klammern eingeschlossene Befehlsgruppierung. Beispiel:

( pwd ; (echo $BASH_SUBSHELL)) 

Dadurch werden das aktuelle Arbeitsverzeichnis und die Anzahl der erzeugten Shells gedruckt. HINWEIS Hervorrufen Subshell ist teuer.

2. Coprozess

Es erzeugt eine Unterschale im Hintergrundmodus und führt einen Befehl innerhalb dieser Unterschale aus.

coproc sleep 10

Wenn Sie einen jobsBefehl eingeben

[1]+  Running                 coproc COPROC sleep 10 &

Sie sehen den Schlaf als Hintergrundprozess, der im Hintergrund ausgeführt wird.

Forking eines untergeordneten Prozesses

Ein untergeordneter Prozess beim Rechnen ist ein Prozess, der von einem anderen Prozess erstellt wird. Immer wenn ein externer Befehl ausgeführt wird, wird ein untergeordneter Prozess erstellt. Diese Aktion wird als Gabeln bezeichnet.

$ps -f
UID        PID  PPID  C STIME TTY          TIME CMD  
umcr7     3647  3638  0 13:54 pts/0    00:00:00 bash
umcr7     3749  3647  0 13:59 pts/0    00:00:00 ps -f

Ebenso ps -fwie der externe Befehl (dh ein externer Befehl, der manchmal als Dateisystembefehl bezeichnet wird, ist ein Programm, das außerhalb der Bash-Shell vorhanden ist). Dadurch wird ein untergeordneter Prozess mit der übergeordneten ID der Bash-Shell erstellt, von der aus er ausgeführt wird.

Muhammad Umar Amanat
quelle
0

Beide (Subshell und untergeordnete Shell) sind ein separater Prozess als die übergeordnete Shell (beide sind untergeordnete Elemente der übergeordneten Shell). Das heißt, sie haben unterschiedliche PIDs. Und beide beginnen mit einer Abzweigung (Kopie) der übergeordneten Shell.

Eine Subshell ist eine Kopie der übergeordneten Shell, in der Variablen, Funktionen, Flags und alles wie in der übergeordneten Shell verfügbar sind. Änderungen solcher Werte wirken sich nicht auf das übergeordnete Element aus.

Eine untergeordnete Shell startet als Fork, wird jedoch auf die durch die Startkonfigurationen angegebenen Shell-Standardwerte zurückgesetzt. Es wird zu einem Prozess, mit dem Code ausgeführt wird (entweder eine Shell oder ein Befehl).

Eine Unterschale kann auf Variablenwerte zugreifen:

$ x=123; ( echo "$x")
123

Eine untergeordnete Shell konnte nicht (nicht exportierte Variablen):

$ x=234; sh -c 'echo "x=$x"'
x=
Isaac
quelle