Wie verbinde ich unter Linux zwei Named Pipes zu einem einzigen Eingabestream?

64

Mit der Funktion pipes ( |) unter Linux kann ich die Standardeingabe an einen oder mehrere Ausgabestreams weiterleiten.

Ich kann verwenden tee, um die Ausgabe zu teilen, um Unterprozesse zu trennen.

Gibt es einen Befehl zum Verbinden von zwei Eingabestreams?

Wie würde ich das machen? Wie funktioniert Diff?

Cristian Ciupitu
quelle

Antworten:

105

Persönlich mein Favorit (erfordert Bash und andere Dinge, die bei den meisten Linux-Distributionen Standard sind)

Die Details können sehr davon abhängen, was die beiden Dinge ausgeben und wie Sie sie zusammenführen möchten ...

Inhalt von command1 und command2 nacheinander in der Ausgabe:

cat <(command1) <(command2) > outputfile

Oder wenn beide Befehle alternative Versionen derselben Daten ausgeben, die Sie nebeneinander anzeigen möchten (ich habe dies mit snmpwalk verwendet; Zahlen auf der einen Seite und MIB-Namen auf der anderen Seite):

paste <(command1) <(command2) > outputfile

Oder wenn Sie die Ausgabe von zwei ähnlichen Befehlen vergleichen möchten (z. B. eine Suche in zwei verschiedenen Verzeichnissen)

diff <(command1) <(command2) > outputfile

Oder wenn es sich um sortierte Ausgaben handelt, führen Sie diese zusammen:

sort -m <(command1) <(command2) > outputfile

Oder führe beide Befehle gleichzeitig aus (könnte allerdings ein bisschen durcheinander bringen):

cat <(command1 & command2) > outputfile

Der Operator <() richtet für jeden Befehl eine Named Pipe (oder / dev / fd) ein, leitet die Ausgabe dieses Befehls in die Named Pipe (oder / dev / fd-Dateihandle-Referenz) und übergibt den Namen in der Befehlszeile. Es gibt eine Entsprechung mit> (). Sie command0 | tee >(command1) >(command2) >(command3) | command4können beispielsweise die Ausgabe eines Befehls gleichzeitig an vier andere Befehle senden.

freiheit
quelle
genial! Ich habe die Manpage von Bash viel gelesen, aber diese Seite nicht ausgewählt
Javier
2
Sie finden die Referenz im [Advanced Bash Scripting Guide] ( tldp.org/LDP/abs/html/process-sub.html ) im Linux-Dokumentationsprojekt
Brice,
3
Ich konnte Interleaved Lines durch Piping-Through verhindern grep --line-buffered- praktisch, um mehrere Protokolldateien gleichzeitig grepzu bearbeiten tail. Siehe stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO
16

Sie können zwei Dämpfe an einen anderen anhängen cat, wie der Gorilla zeigt.

Sie können auch ein FIFO erstellen, die Ausgabe der Befehle darauf richten und dann mit einem beliebigen anderen Programm aus dem FIFO lesen:

mkfifo ~/my_fifo
command1 > ~/my_fifo &
command2 > ~/my_fifo &
command3 < ~/my_fifo

Besonders nützlich für Programme, die nur eine Datei schreiben oder lesen oder Programme, die nur stdout / file ausgeben, mit einem Programm mischen, das nur das andere unterstützt.

Chris S
quelle
2
Dieser funktioniert unter pfSense (FreeBSD), die akzeptierte Antwort jedoch nicht. Danke!
Nathan
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1und /tmp/p2sind Ihre Input-Pipes, während /tmp/outputder Output ist.

Gorilla
quelle
6
Hinweis: Wenn nicht beide Befehle neben dem ()Flush ihrer Ausgabe in jeder Zeile (und einigen anderen undurchsichtigen POSIX-Regeln für die Atomarität) stehen, könnten Sie am Eingang von cat ...
freiheit
Sollten Sie kein Semikolon anstelle von Et-Zeichen verwenden?
Samir
Das ist episches Zeug
Mobigital
5

Ich habe dafür ein spezielles Programm erstellt: fdlinecombine

Es liest mehrere Pipes (normalerweise Programmausgaben) und schreibt sie zeilenweise auf stdout (Sie können auch das Trennzeichen überschreiben)

Vi.
quelle
Funktioniert wie angegeben. Vielen Dank für die Veröffentlichung.
Alexei
3

Ein wirklich cooler Befehl, den ich dafür verwendet habe, ist tpipe, dass Sie möglicherweise kompilieren müssen, da er nicht so häufig vorkommt. Es ist wirklich großartig, genau das zu tun, wovon du sprichst, und es ist so sauber, dass ich es normalerweise installiere. Die Manpage befindet sich hier http://linux.die.net/man/1/tpipe . Der aktuell aufgeführte Download befindet sich in diesem Archiv unter http://www.eurogaran.com/downloads/tpipe/ .

Es wird so verwendet,

## Reinject sub-pipeline stdout into standard output:
$ pipeline1 | tpipe "pipeline2" | pipeline3
JM Becker
quelle
3

Sei hier vorsichtig; Durch einfaches Catting werden die Ergebnisse auf eine Weise gemischt, die Sie möglicherweise nicht möchten. Wenn es sich beispielsweise um Protokolldateien handelt, möchten Sie wahrscheinlich nicht wirklich, dass eine Zeile von einer zur Hälfte durch eine Zeile von der anderen eingefügt wird. Wenn das in Ordnung ist, dann

tail -f / tmp / p1 / tmp / p2> / tmp / output

wird funktionieren. Wenn das nicht in Ordnung ist, müssen Sie etwas finden, das die Zeilenpufferung übernimmt und nur vollständige Zeilen ausgibt. Syslog macht das, aber ich bin mir nicht sicher, was sonst könnte.

EDIT: Optimierung für ungepuffertes Lesen und Named Pipes:

Betrachtet man / tmp / p1, / ​​tmp / p2, / tmp / p3 als Named Pipes, erstellt von "mkfifo / tmp / p N "

tail -q -f / tmp / p1 / tmp / p2 | awk '{print $ 0> "/ tmp / p3"; close ("/ tmp / p3"); fflush ();} '&

Jetzt können wir auf diese Weise die Ausgabe der Named Pipe "/ tmp / p3" ungepuffert lesen :

Schwanz -f / tmp / p3

Es gibt einen kleinen Fehler der Art, Sie müssen die 1. Input Pipe / tmp / p1 "initialisieren" durch:

echo -n> / tmp / p1

Damit wird Tail die Eingabe von 2nd Pipe / tmp / p2 zuerst akzeptieren und nicht warten, bis etwas zu / tmp / p1 kommt. Dies ist möglicherweise nicht der Fall, wenn Sie sicher sind, dass das / tmp / p1 zuerst Eingaben empfängt.

Auch die Option -q ist , um benötigt Schwanz nicht Müll über Dateinamen drucken.

pjz
quelle
das nützlichere ist: "tail -q -f / tmp / p1 / tmp / p2 | another_command", da es zeilenweise ausgeführt wird und mit der Option -q keinen anderen Müll
ausgibt
für ungepufferte Datei / Named Pipe verwenden: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & Jetzt kann das / tmp / p3 sogar Named Pipe sein und Sie können es lesen, indem einfach tail -f /tmp/p3alles UNBUFFERED ist = Zeile für Zeile gibt es jedoch einen kleinen Fehler. Die erste Datei / Named Pipe muss zuerst initialisiert werden, damit Tail die Ausgabe von der zweiten akzeptiert. Sie müssen also echo -n > /tmp/p1und dann wird alles reibungslos funktionieren.
Readyblue
1

Das beste Programm dafür ist lmerge. Im Gegensatz zu Freiharts Antwort ist sie zeilenorientiert, sodass sich die Ausgabe der beiden Befehle nicht gegenseitig stört. Im Gegensatz zu anderen Lösungen wird die Eingabe fair zusammengeführt, sodass kein Befehl die Ausgabe dominieren kann. Zum Beispiel:

$ lmerge <(yes foo) <(yes bar) | head -n 4

Ausgabe von:

foo
bar
foo
bar
Rian Hunter
quelle