Wie Bash behandelt ">> ()"

9

Beim Experimentieren mit der Umleitung von Ausgaben und der Substitution von Prozessen bin ich auf den folgenden Befehl und die daraus resultierende Ausgabe gestoßen:

    me @ elem: ~ $ echo foo >> (cat); Echobar
    Bar
    me @ elem: ~ $ foo

(Ja, diese leere Zeile am Ende ist beabsichtigt.)

Bash-Echo-Leiste, druckt meine übliche Eingabeaufforderung, Echo-Foo, Echo ist eine neue Zeile und lässt meinen Cursor dort. Wenn ich erneut die Eingabetaste drücke, wird meine Eingabeaufforderung in einer neuen Zeile gedruckt und der Cursor folgt ihr (wie erwartet, wenn jemand in einer leeren Befehlszeile die Eingabetaste drückt).

Ich hatte erwartet, dass es foo in einen Dateideskriptor schreibt, cat es liest und echo's foo, die Leiste des zweiten Echoechos, und dann zurück zur Eingabeaufforderung. Das ist aber eindeutig nicht der Fall.

Könnte jemand bitte erklären, was los ist?

Stanley Yu
quelle
Ich möchte vorschlagen, die Antworten dazu zu suchen: unix.stackexchange.com/questions/182800/… Es erklärt die doppelte Umleitung und erklärt, warum Sie mit unterschiedlichen Ergebnissen enden. Sowohl Muru als auch Michael Hormers.
Keine Zeit
Eine Frage, die explizit behandelt, warum die Ausgabe der Prozessersetzung in einigen Versionen der Bourne Again-Shell nach der Eingabeaufforderung angezeigt wird (und unter bestimmten Umständen überhaupt nicht angezeigt wird ), finden Sie unter unix.stackexchange.com/questions/471987 .
JdeBP

Antworten:

9

Je nach Zeitpunkt wird möglicherweise foovor bar, nach baroder sogar nach der Eingabeaufforderung angezeigt . Fügen Sie eine kleine Verzögerung hinzu, um ein konsistentes Timing zu erhalten:

$ echo foo > >(sleep 1; cat); echo bar; sleep 2 
bar
foo
$

barerscheint sofort, dann foonach einer Sekunde, dann die nächste Eingabeaufforderung nach einer weiteren Sekunde.

Was passiert ist, dass bash Prozessersetzungen im Hintergrund ausführt.

  1. Der Haupt-Bash-Prozess startet die Ausführung einer Subshell sleep 1; catund richtet eine Pipe dazu ein.
  2. Der Haupt-Bash-Prozess wird ausgeführt echo foo. Da dies den Pipe-Puffer nicht ausfüllt, wird der echoBefehl ohne Blockierung beendet.
  3. Der Haupt-Bash-Prozess wird ausgeführt echo bar.
  4. Der Haupt-Bash-Prozess startet den Befehl sleep 2.
  5. Währenddessen startet die Subshell den Befehl sleep 1.
  6. sleep 1Kehrt nach ca. 1 Sekunde in den Unterprozess zurück. Der Unterprozess wird fortgesetzt cat.
  7. cat kopiert seine Eingabe in seine Ausgabe (die auf dem Bildschirm angezeigt wird) und kehrt zurück.
  8. Die Unterschale hat ihre Arbeit beendet und wird beendet.
  9. Nach einer weiteren Sekunde sleep 2kehrt zurück. Der Haupt-Shell-Prozess wird ausgeführt und Sie sehen die nächste Eingabeaufforderung.
Gilles 'SO - hör auf böse zu sein'
quelle
3

Sie benötigen keine Prozessersetzung, um diesen Effekt zu erzielen. Versuche dies:

( echo foo | cat & )

Sie erhalten fast das gleiche Ergebnis (ohne das bar; ich lasse das als Übung) und aus dem gleichen Grund. In beiden Fällen catwird als Hintergrundaufgabe gestartet. In meiner Zeile hier ist das explizit. Im Fall der Prozessersetzung ist dies ebenfalls explizit - es handelt sich um einen separaten Prozess, der an einen Namensdateideskriptor angehängt ist -, aber möglicherweise nicht so offensichtlich.

Der untergeordnete Prozess wird nicht unbedingt beendet, bevor bashdie nächste Eingabeaufforderung gedruckt wird. Und da seine Ausgabe gepuffert ist, gibt es nichts aus, bis es beendet wird. Zu diesem Zeitpunkt wurde bash gerade $auf stderr gedruckt , und jetzt wird der Hintergrundprozess nach dem Drucken foound einer neuen Zeile beendet.

Rici
quelle