Bash: Prozesssubstitution und stdin

13

Die folgende Zeile ist offensichtlich:

echo "bla" | foo | bar

Aber machen die folgenden dasselbe?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

Welcher von den foound barlas "bla" von stdin und warum?

Ich meine, dass ich es natürlich einfach codieren und überprüfen kann, aber ich bin mir nicht sicher, ob es ein definiertes Verhalten ist oder ob ich Funktionen ausnutze, auf die ich mich nicht verlassen sollte.

etam1024
quelle

Antworten:

9

Das ist shellabhängig und nicht AFAICS dokumentiert. In kshund teilen sich bashim ersten Fall foodie gleichen Werte wie bar. Sie werden für die Ausgabe von kämpfen echo.

So zum Beispiel in,

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

Sie sehen Beweise, pastedie jeden anderen Textblock aus seqder Ausgabe trlesen, während die anderen gelesen werden.

Mit zshruft es das äußere stdin ab (es sei denn, es ist ein Terminal und die Shell ist nicht interaktiv. In diesem Fall wird sie umgeleitet von /dev/null). ksh(woher es stammt) zshund bashsind die einzigen Bourne-ähnlichen Shells mit Unterstützung für die Prozesssubstitution AFAIK.

In zu echo "bla" | bar < <(foo)beachten , dass bars stdin wird das Rohr durch den Ausgang der gespeist werden foo. Das ist gut definiertes Verhalten. In diesem Fall scheint es so, fooals sei stdin die Pfeife, von der echoin all ksh, zshund gespeist wird bash.

Wenn Sie ein konsistentes Verhalten für alle drei Shells haben und zukunftssicher sein möchten, da sich das Verhalten möglicherweise ändert, da es nicht dokumentiert ist, würde ich Folgendes schreiben:

echo bla | { bar <(foo); }

Um sicher zu gehen foo, ist stdin auch die Pipe von echo(ich kann nicht verstehen, warum du das machen möchtest). Oder:

echo bla | bar <(foo < /dev/null)

Um sicherzustellen , dass foosie nicht aus dem Rohr aus lesen echo. Oder:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

Um foo's stdin das äußere stdin wie in aktuellen Versionen von zu haben zsh.

Stéphane Chazelas
quelle
"In diesem Fall ist foo's stdin die Pfeife, die durch Echo in ksh, zsh und bash gespeist wird." Sie haben das gerade von Hand getestet, oder ist es irgendwo dokumentiert?
Etam1024
Verweist "im ersten Fall" in der ersten Zeile auf "|" foo | bar` oder `| bar <(foo) `?
Volker Siegel
4

echo "bla" | foo | bar: Die Ausgabe von echo "bla"wird an umgeleitet foo, deren Ausgabe an umgeleitet wird bar.

echo "bla" | bar <(foo): Das leitet die Ausgabe von echo "bla"an bar. Wird baraber mit einem Argument ausgeführt. Das Argument ist der Pfad zum Dateideskriptor, an den die Ausgabe von foogesendet wird. Dieses Argument verhält sich wie eine Datei, die die Ausgabe von enthält foo. Das ist also nicht dasselbe.

echo "bla" | bar < <(foo): Man kann davon ausgehen, dass die Ausgabe von an echo "bla"gesendet werden soll barund die gesamte Anweisung der ersten entspricht. Aber das ist nicht richtig. Folgendes passiert: Da die Eingabeumleitung <nach der Pipe ( |) ausgeführt wird, wird sie überschrieben . Ist echo "bla"also nicht zur Stange geleitet. Stattdessen wird die Ausgabe von fooals Standardeingabe an umgeleitet bar. Um dies zu beheben, lesen Sie den folgenden Befehl und die Ausgabe:

$ echo "bla" | cat < <(echo "foo")
foo

Wie Sie sehen, echo "bla"wird durch abgelöst echo "foo".

Sehen Sie sich nun diesen Befehl an:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

Also echo "bar"wird an weitergeleitet awk, was stdin liest und den String and foozur Ausgabe hinzufügt . Dieser Ausgang wird weitergeleitet cat.

Chaos
quelle
Und meine Frage ist: "Ist die Tatsache, dass awk" bar "lautet, ein definiertes Verhalten?"
Etam1024
Ja ist es. cmd1 < <(cmd2)verhält sich genauso wie cmd2 | cmd1.
Chaos
Oder cmd1 | cmd2 | cmd3ist das gleiche wiecmd1 | cmd3 < <(cmd2)
Chaos
3
Wenn es Wikipedia wäre, würde ich Ihre Aussagen mit einem "Zitat benötigt" -Tag versehen :) Der springende Punkt meiner Frage ist, dass es so funktioniert, wie Sie es sagen, aber ich konnte keine Dokumentation dazu finden.
Etam1024