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.