Ja, in bash
like in ksh
(woher die Funktion stammt) wird nicht auf die Prozesse innerhalb der Prozessersetzung gewartet (bevor der nächste Befehl im Skript ausgeführt wird).
Für <(...)
einen ist das normalerweise in Ordnung wie in:
cmd1 <(cmd2)
Die Shell wartet darauf cmd1
und cmd1
wartet normalerweise darauf, cmd2
bis das Dateiende in der ersetzten Pipe abgelesen wird. Das Dateiende tritt normalerweise auf, wenn die Pipe cmd2
stirbt. Das ist der gleiche Grund , mehrere Schalen (nicht bash
) nicht warten , stören cmd2
in cmd2 | cmd1
.
Dies cmd1 >(cmd2)
ist jedoch in der Regel nicht der Fall, da in der Regel mehr cmd2
darauf gewartet cmd1
wird, bis das Programm beendet ist.
Das ist darin behoben, zsh
dass cmd2
dort gewartet wird (aber nicht, wenn Sie es als schreiben cmd1 > >(cmd2)
und cmd1
es nicht eingebaut ist, verwenden Sie es {cmd1} > >(cmd2)
stattdessen wie dokumentiert ).
ksh
wait
Wartet nicht standardmäßig, sondern lässt dich mit dem eingebauten Programm darauf warten (es stellt auch die PID in zur Verfügung $!
, obwohl das nicht hilft, wenn du das tust cmd1 >(cmd2) >(cmd3)
)
rc
(mit der cmd1 >{cmd2}
Syntax), mit der ksh
Ausnahme, dass Sie die Pids aller Hintergrundprozesse mit erhalten können $apids
.
es
(auch mit cmd1 >{cmd2}
) wartet auf cmd2
like in zsh
und wartet auch auf cmd2
in <{cmd2}
Bearbeitung befindliche Weiterleitungen.
bash
cmd2
Stellt die PID von (oder genauer gesagt von der Subshell, da sie cmd2
in einem untergeordneten Prozess dieser Subshell ausgeführt wird, obwohl dies der letzte Befehl dort ist) in zur Verfügung $!
, lässt Sie jedoch nicht darauf warten.
Wenn Sie verwenden müssen bash
, können Sie das Problem umgehen, indem Sie einen Befehl verwenden, der auf beide Befehle wartet:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Das macht beides cmd1
und cmd2
hat ihre fd 3 zu einer Pfeife geöffnet. cat
Wartet auf das Dateiende am anderen Ende, wird also normalerweise nur beendet, wenn beide beendet sind cmd1
und cmd2
tot sind. Und die Shell wartet auf diesen cat
Befehl. Sie können dies als ein Netz betrachten, um die Beendigung aller Hintergrundprozesse &
abzufangen (Sie können es für andere Dinge verwenden, die im Hintergrund gestartet wurden , z. B. für Coprocs oder sogar für Befehle, die selbst im Hintergrund ausgeführt werden, vorausgesetzt, sie schließen nicht alle ihre Dateideskriptoren, wie es Daemons normalerweise tun ).
Beachten Sie, dass es dank des oben erwähnten verschwendeten Subshell-Prozesses auch dann funktioniert, wenn cmd2
fd 3 geschlossen wird (Befehle tun dies normalerweise nicht, aber einige mögen sudo
oder ssh
tun dies). Zukünftige Versionen von bash
können eventuell die Optimierung dort wie in anderen Shells durchführen. Dann brauchen Sie etwas wie:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Um sicherzustellen, dass es noch einen zusätzlichen Shell-Prozess gibt, bei dem fd 3 geöffnet ist und auf diesen sudo
Befehl wartet .
Beachten Sie, dass cat
nichts gelesen wird (da die Prozesse nicht auf ihre fd 3 schreiben). Es ist nur für die Synchronisation da. Es wird nur ein read()
Systemaufruf ausgeführt, der am Ende nichts zurückgibt.
Sie können das Ausführen tatsächlich vermeiden, cat
indem Sie eine Befehlsersetzung verwenden, um die Pipesynchronisierung durchzuführen:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Diesmal ist es die Shell cat
, die aus der Pipe liest, deren anderes Ende auf fd 3 von cmd1
und offen ist cmd2
. Wir verwenden eine variable Zuweisung, damit der Exit-Status von cmd1
in verfügbar ist $?
.
Oder Sie können die Prozessersetzung von Hand durchführen und dann sogar die Ihres Systems verwenden, sh
da dies zur Standard-Shell-Syntax werden würde:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
obwohl zur Kenntnis , wie bereits festgestellt , dass nicht alle sh
Implementierungen für warten würden , cmd1
nachdem cmd2
beendet (obwohl das besser ist , als umgekehrt). Diese Zeit $?
enthält den Exit-Status von cmd2
; obwohl bash
und zsh
make cmd1
‚s Exit - Status in ${PIPESTATUS[0]}
und $pipestatus[1]
jeweils (siehe auch die pipefail
Option in einigen Schalen so $?
kann berichten , das Versagen von Rohrkomponenten außer den letzten)
Beachten Sie, dass yash
ähnliche Probleme mit seinem Prozess hat Umleitung Funktion. cmd1 >(cmd2)
würde dort geschrieben cmd1 /dev/fd/3 3>(cmd2)
werden. Aber es cmd2
wird nicht darauf gewartet, und Sie können auch nicht wait
darauf warten, und die pid wird auch nicht in der $!
Variablen verfügbar gemacht . Sie würden die gleichen Workarounds wie für verwenden bash
.