Come posso unire due pipe nominate in un singolo flusso di input in Linux


64

Usando la funzione pipe ( |) in Linux, posso inoltrare l'input standard a uno o più flussi di output.

Posso usare teeper dividere l'output per separare i processi secondari.

Esiste un comando per unire due flussi di input?

Come lo farei? Come funziona diff?

Risposte:


105

Personalmente, il mio preferito (richiede bash e altre cose standard nella maggior parte delle distribuzioni Linux)

I dettagli possono dipendere molto dall'output delle due cose e da come si desidera unirle ...

Contenuto di command1 e command2 uno dopo l'altro nell'output:

cat <(command1) <(command2) > outputfile

O se entrambi i comandi generano versioni alternative degli stessi dati che si desidera vedere fianco a fianco (l'ho usato con snmpwalk; numeri su un lato e nomi MIB sull'altro):

paste <(command1) <(command2) > outputfile

O se vuoi confrontare l'output di due comandi simili (dì una ricerca su due diverse directory)

diff <(command1) <(command2) > outputfile

O se vengono ordinati output di qualche tipo, uniscili:

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

Oppure esegui entrambi i comandi contemporaneamente (potrebbe mescolare un po 'le cose, però):

cat <(command1 & command2) > outputfile

L'operatore <() imposta una pipe denominata (o / dev / fd) per ciascun comando, eseguendo il piping dell'output di quel comando nella pipe denominata (o riferimento al filehandle / dev / fd) e passa il nome sulla riga di comando. C'è un equivalente con> (). Potresti fare: command0 | tee >(command1) >(command2) >(command3) | command4per inviare simultaneamente l'output di un comando ad altri 4 comandi, ad esempio.


eccezionale! Ho letto la manpage di bash un sacco di tempo ma non l'ho scelto
— Javier,

2
Puoi trovare il riferimento nella [guida di scripting bash avanzata] ( tldp.org/LDP/abs/html/process-sub.html ) al progetto di documentazione di Linux
— brice

3
sono stato in grado di prevenire le linee interlacciate convogliando attraverso grep --line-buffered- comodo per concomitanza grep'ing il taildi più file di log. vedi stackoverflow.com/questions/10443704/line-buffered-cat
— RubyTuesdayDONO

16

Puoi aggiungere due vapori a un altro con cat, come mostra il gorilla.

Puoi anche creare un FIFO, indirizzare l'output dei comandi a quello, quindi leggere dal FIFO con qualunque altro programma:

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

Particolarmente utile per i programmi che scriveranno o leggeranno solo un file o mescoleranno i programmi che generano solo stdout / file con uno che supporta solo l'altro.


2
Questo funziona su pfSense (FreeBSD) mentre la risposta accettata no. Grazie!
— Nathan,

9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1e /tmp/p2sono le tue pipe di input, mentre /tmp/outputè l'output.


6
Nota: A meno che entrambi i comandi a lato non ()scarichino l'output su ogni riga (e alcune altre oscure regole POSIX per l'atomicità), potresti finire con qualche strana confusione sull'input per cat ...
— Freiheit

Non dovresti usare il punto e virgola anziché il carattere e commerciale?
— Samir,

questa è roba epica
— Mobigital

5

Ho creato un programma speciale per questo: fdlinecombine

Legge più pipe (in genere uscite di programma) e le scrive su stdout in modo lineare (è anche possibile ignorare il separatore)


Funziona come pubblicizzato. Grazie per averlo reso pubblico.
— alexei,

3

Un comando davvero interessante che ho usato per questo è tpipeche potresti doverlo compilare perché non è così comune. È davvero ottimo per fare esattamente ciò di cui stai parlando, ed è così pulito che di solito lo installo. La pagina man si trova qui http://linux.die.net/man/1/tpipe . Il download attualmente elencato si trova in questo archivio http://www.eurogaran.com/downloads/tpipe/ .

È usato così,

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

3

Stai attento qui; solo catturarli finirà per mescolare i risultati in modi che potresti non desiderare: ad esempio, se sono file di registro, probabilmente non vuoi davvero una linea da una inserita a metà strada attraverso una linea dall'altra. Se va bene, allora

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

funzionerà. Se ciò non va bene, allora dovrai trovare qualcosa che eseguirà il buffering delle linee e produrrà solo linee complete. Syslog lo fa, ma non sono sicuro di cos'altro.

EDIT: ottimizzazione per letture senza buffer e named pipe:

considerando / tmp / p1, / ​​tmp / p2, / tmp / p3 come named pipe, creato da "mkfifo / tmp / p N "

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

ora in questo modo, possiamo leggere l'output denominato pipe "/ tmp / p3" senza buffer in base a:

tail -f / tmp / p3

c'è un piccolo bug di ordinamento, è necessario "inizializzare" il primo input pipe / tmp / p1:

echo -n> / tmp / p1

per accodare accetterà prima l'input dal 2 ° pipe / tmp / p2 e non aspetterà che qualcosa arrivi a / tmp / p1. questo potrebbe non essere il caso, se sei sicuro, / tmp / p1 riceverà prima l'input.

Anche l'opzione -q è necessaria al fine di coda non stampa spazzatura su nomi di file.


il più utile sarà: "tail -q -f / tmp / p1 / tmp / p2 | altro_comando" in quanto sarà fatto riga per riga e con l'opzione -q non stamperà nessun'altra spazzatura
— readyblue

per file senza buffer / uso di pipe con nome: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & ora / tmp / p3 può anche essere chiamato pipe e puoi leggerlo semplicemente tail -f /tmp/p3tutto questo è UNBUFFERED = riga per riga c'è comunque un piccolo bug di ordinamento. il primo file / pipe chiamato deve essere inizializzato per primo in modo che tail accetti l'output dal 2 °. quindi dovrai echo -n > /tmp/p1e di tutto funzionerà senza intoppi.
— readyblue,

1

Il miglior programma per farlo è lmerge. A differenza della risposta di Freihart, è orientata alla linea, quindi l'output dei due comandi non si bloccherà a vicenda. A differenza di altre soluzioni, unisce correttamente l'input, quindi nessun comando può dominare l'output. Per esempio:

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

Fornisce un output di:

foo
bar
foo
bar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.