Ja, in bashlike 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 cmd1und cmd1wartet normalerweise darauf, cmd2bis das Dateiende in der ersetzten Pipe abgelesen wird. Das Dateiende tritt normalerweise auf, wenn die Pipe cmd2stirbt. Das ist der gleiche Grund , mehrere Schalen (nicht bash) nicht warten , stören cmd2in cmd2 | cmd1.
Dies cmd1 >(cmd2)ist jedoch in der Regel nicht der Fall, da in der Regel mehr cmd2darauf gewartet cmd1wird, bis das Programm beendet ist.
Das ist darin behoben, zshdass cmd2dort gewartet wird (aber nicht, wenn Sie es als schreiben cmd1 > >(cmd2)und cmd1es nicht eingebaut ist, verwenden Sie es {cmd1} > >(cmd2)stattdessen wie dokumentiert ).
kshwaitWartet 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 kshAusnahme, dass Sie die Pids aller Hintergrundprozesse mit erhalten können $apids.
es(auch mit cmd1 >{cmd2}) wartet auf cmd2like in zshund wartet auch auf cmd2in <{cmd2}Bearbeitung befindliche Weiterleitungen.
bashcmd2Stellt die PID von (oder genauer gesagt von der Subshell, da sie cmd2in 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 cmd1und cmd2hat ihre fd 3 zu einer Pfeife geöffnet. catWartet auf das Dateiende am anderen Ende, wird also normalerweise nur beendet, wenn beide beendet sind cmd1und cmd2tot sind. Und die Shell wartet auf diesen catBefehl. 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 cmd2fd 3 geschlossen wird (Befehle tun dies normalerweise nicht, aber einige mögen sudooder sshtun dies). Zukünftige Versionen von bashkö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 sudoBefehl wartet .
Beachten Sie, dass catnichts 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, catindem 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 cmd1und offen ist cmd2. Wir verwenden eine variable Zuweisung, damit der Exit-Status von cmd1in verfügbar ist $?.
Oder Sie können die Prozessersetzung von Hand durchführen und dann sogar die Ihres Systems verwenden, shda 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 shImplementierungen für warten würden , cmd1nachdem cmd2beendet (obwohl das besser ist , als umgekehrt). Diese Zeit $?enthält den Exit-Status von cmd2; obwohl bashund zshmake cmd1‚s Exit - Status in ${PIPESTATUS[0]}und $pipestatus[1]jeweils (siehe auch die pipefailOption 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 cmd2wird nicht darauf gewartet, und Sie können auch nicht waitdarauf warten, und die pid wird auch nicht in der $!Variablen verfügbar gemacht . Sie würden die gleichen Workarounds wie für verwenden bash.