2015-11-17 16 views
10

Beim Entwerfen einer Kette von Befehlen, um eine bestimmte Aufgabe auszuführen, stieß ich auf das Problem, dass sich anonyme Pipes nicht wie erwartet verhalten. Da der ursprüngliche Befehl, den ich ausführe, zu komplex ist, um hier zu erklären, habe ich ein Beispiel erstellt, das das Problem zeigt (ich weiß, dass all diese Befehle im Grunde nichts tun). Außerdem verwende ich pv, um zu zeigen, ob die Daten tatsächlich von Eingabe zu Ausgabe kopiert werden.Bash Anonyme Pipes

cat /dev/zero | pv > /dev/null 

Dies funktioniert wie erwartet. (Kopieren von Daten von/dev/null/dev/null)

cat /dev/zero | tee /dev/null | pv > /dev/null 

Dies auch wie erwartet funktioniert (die Daten duplizieren und beiden Kopien auf/dev/null senden)

cat /dev/zero | tee >(pv -c > /dev/null) | pv -c > /dev/null 

Dieser Befehl ist nur teilweise funktioniert. Während die Kopie von STDIN nach STDOUT immer noch funktioniert (ein pv wird den Fortschritt für kurze Zeit anzeigen), wird der ganze Befehl von der anonymen Pipe blockiert, die nichts erhält und somit T-Boxen, da einer der Ausgänge nicht beschrieben werden kann (Ich habe das überprüft, indem ich es in Dateien anstatt in/dev/null schreiben ließ).

Wenn jemand eine Idee hat, warum das nicht funktioniert (wie erwartet?) In bash, würde ich mich für die Hilfe freuen.

PS: Wenn ich zsh statt bash verwende, läuft der Befehl wie erwartet. Unglücklicherweise hat das System, auf dem es ausgeführt werden muss, keine zsh und es gibt keine Möglichkeit für mich, zsh auf diesem System zu installieren.

+0

Wird direkt über 'bash -c' oder in einer Subshell ausgeführt (zB:' (cat/dev/zero | tee> (pv -c>/dev/null) | pv -c>/dev/null) ') scheint zu funktionieren ... wenn es in einer interaktiven Shell läuft, hängt es wie du erwähnt hast. Ich habe keine Idee warum. – FatalError

+1

Passiert das nur mit 'pv'? Denn wenn ich das erste 'pv' durch' cat' substituiere, funktioniert es für mich. Vielleicht funktioniert 'pv' einfach nicht mit Prozesssubstitutionsmagie? –

+0

Soweit ich weiß, liest Katze nicht von STDIN. Durch Ersetzen des ersten pv durch cat ignoriert das Lesen der anonymen Pipe effektiv die anonyme Weiterleitung. Ich glaube nicht, dass das der gewünschte Effekt ist. Allerdings hat das Ersetzen von pv durch etwas anderes (wie awk '{print $ 0}' oder perl -ne 'print $ _' den gleichen Effekt (beide Befehle kopieren STDIN effektiv nach STDOUT) – Fabraxias

Antwort

1

Wenn Sie <(...) für Prozesssubstitution verwenden, hat der Prozess, der darin ausgeführt wird, kein steuerndes Terminal. Aber pv zeigt immer seine Ergebnisse an das Terminal; Wenn es keine gibt, wird es gestoppt.

Wenn Sie Ihren Code und ausführen, während er läuft, eine ps axf tun, werden Sie etwas sehen:

23412 pts/16 S  0:00 \_ bash 
24255 pts/16 S+  0:00  \_ cat /dev/zero 
24256 pts/16 S+  0:00  \_ tee /dev/fd/63 
24258 pts/16 S  0:00  | \_ bash 
24259 pts/16 T  0:00  |  \_ pv -c 
24257 pts/16 S+  0:00  \_ pv -c 

..., die Ihnen sagt, dass die innerhalb der Prozesssubstitution (die ausgeführt pv -c eine unter der zweiten bash) ist in T Zustand, gestoppt. Es wartet darauf, ein kontrollierendes Terminal zu haben, um zu laufen. Es hat keine, also wird es für immer aufhören, und bash hört schließlich auf, Daten an diese Pipe zu senden.

+0

mhm - ok, das verstehe ich für <() - das leitet STDIN der Subshell von einer anonymen Pipe in die Outshell um. Also, eine "Katze <(gunzip -c some.gz) zu tun" würde tatsächlich funktionieren (ja, es ist ein weiterer nutzloser Befehl und ein sehr umständlicher Weg für zcat). Aber soweit ich es verstehe, macht>() genau das Gegenteil - leitet den Output von der äußeren Shell über eine anonyme Pipe an die innere Shell um. Mit anderen Worten, sollte/dev/fd/63 nicht die automatische Eingabe für das gestoppte PV sein? – Fabraxias