Jak połączyć dwie nazwane potoki w pojedynczy strumień wejściowy w systemie Linux

64

Korzystając z funkcji potoki ( |) w systemie Linux, mogę przekazać standardowe wejście do jednego lub kilku strumieni wyjściowych.

Mogę użyć teedo podzielenia danych wyjściowych na oddzielne podprocesy.

Czy istnieje polecenie połączenia dwóch strumieni wejściowych?

Jak miałbym to zrobić? Jak działa diff?

Cristian Ciupitu
źródło

Odpowiedzi:

105

Osobiście mój ulubiony (wymaga bash i innych rzeczy, które są standardowe w większości dystrybucji Linuksa)

Szczegóły mogą bardzo zależeć od tego, co wynikają z dwóch rzeczy i jak chcesz je połączyć ...

Treść poleceń 1 i 2 po sobie w danych wyjściowych:

cat <(command1) <(command2) > outputfile

Lub jeśli obie komendy generują alternatywne wersje tych samych danych, które chcesz zobaczyć obok siebie (użyłem tego z snmpwalk; liczby z jednej strony i nazwy MIB z drugiej):

paste <(command1) <(command2) > outputfile

Lub jeśli chcesz porównać dane wyjściowe dwóch podobnych poleceń (powiedz znaleźć w dwóch różnych katalogach)

diff <(command1) <(command2) > outputfile

Lub jeśli są uporządkowane dane wyjściowe, scal je:

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

Lub uruchom oba polecenia jednocześnie (może to jednak trochę zaszyfrować):

cat <(command1 & command2) > outputfile

Operator <() ustawia nazwany potok (lub / dev / fd) dla każdego polecenia, przesyłając dane wyjściowe tego polecenia do nazwanego potoku (lub odwołania do uchwytu pliku / dev / fd) i przekazuje nazwę w wierszu polecenia. Istnieje odpowiednik> (). Możesz zrobić: command0 | tee >(command1) >(command2) >(command3) | command4na przykład jednocześnie wysłać dane wyjściowe jednego polecenia do 4 innych poleceń.

freiheit
źródło
niesamowite! Dużo czytałem stronę podręcznika basha, ale nie wybrałem tego
Javier,
2
Odniesienie można znaleźć w [zaawansowanym przewodniku skryptów bash] ( tldp.org/LDP/abs/html/process-sub.html ) w projekcie dokumentacji linux
brice
3
I był w stanie zapobiec przeplecione przez linie rurociągów przez grep --line-buffered- przydatny do jednoczesnego grep„ing tailwielu plików dziennika. patrz stackoverflow.com/questions/10443704/line-buffered-cat
RubyT TuesdayDONO
16

Możesz dołączyć dwie pary do drugiej cat, jak pokazuje goryl.

Możesz także utworzyć FIFO, skierować do niego wyjście poleceń, a następnie odczytać z FIFO dowolnym innym programem:

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

Szczególnie przydatny w przypadku programów, które tylko zapisują lub odczytują plik, lub miksuje programy, które wyprowadzają tylko standardowe wyjście / plik z jednym, który obsługuje tylko drugi.

Chris S.
źródło
2
Ten działa na pfSense (FreeBSD), podczas gdy zaakceptowana odpowiedź nie. Dziękuję Ci!
Nathan
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1i /tmp/p2są twoimi potokami wejściowymi, podczas gdy /tmp/outputjest wyjściem.

goryl
źródło
6
Uwaga: O ile obie komendy ()nie wyświetlają danych wyjściowych w każdym wierszu (i innych niejasnych regułach POSIX dotyczących atomowości), możesz skończyć z dziwnym mieszaniem danych wejściowych do cat ...
freiheit
Czy nie powinieneś używać średnika zamiast znaku ampersand?
Samir
to jest
Epickie
5

Stworzyłem do tego specjalny program: fdlinecombine

Odczytuje wiele potoków (zwykle dane wyjściowe programu) i zapisuje je na linii prostej (można również przesłonić separator)

Vi.
źródło
Działa jak w reklamie. Dziękujemy za upublicznienie.
Aleksiej
3

Naprawdę fajnym poleceniem, którego użyłem do tego tpipe, może być konieczność skompilowania, ponieważ nie jest to tak częste. Jest naprawdę świetny do robienia dokładnie tego, o czym mówisz, i jest tak czysty, że zwykle go instaluję. Strona podręcznika znajduje się tutaj http://linux.die.net/man/1/tpipe . Aktualnie wymienione pobieranie znajduje się w tym archiwum http://www.eurogaran.com/downloads/tpipe/ .

Jest używany w ten sposób,

## Reinject sub-pipeline stdout into standard output:
$ pipeline1 | tpipe "pipeline2" | pipeline3
JM Becker
źródło
3

Uważaj tutaj; po prostu ich catting skończy się mieszaniem wyników w sposób, którego możesz nie chcieć: na przykład, jeśli są to pliki dziennika, prawdopodobnie tak naprawdę nie chcesz linii od jednej wstawionej w połowie linii od drugiej. Jeśli to w porządku, to

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

będzie działać. Jeśli to nie jest w porządku, musisz znaleźć coś, co spowoduje buforowanie linii i wyświetli tylko pełne linie. Syslog to robi, ale nie jestem pewien, co jeszcze może być.

EDYCJA: optymalizacja dla niebuforowanego odczytu i nazwanych potoków:

uznanie / tmp / p1, / ​​tmp / p2, / tmp / p3 za nazwane potoki, utworzone przez „mkfifo / tmp / p N

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

teraz w ten sposób możemy odczytać wyjście o nazwie potok „/ tmp / p3” niebuforowane przez:

tail -f / tmp / p3

jest mały rodzaj błędu, musisz „zainicjować” 1. wejściowy potok / tmp / p1 przez:

echo -n> / tmp / p1

aby ogon zaakceptował najpierw dane z 2. rury / tmp / p2 i nie czekał, aż coś dojdzie do / tmp / p1. może nie być tak, jeśli jesteś pewien, że / tmp / p1 otrzyma dane wejściowe jako pierwsze.

Potrzebna jest również opcja -q, aby tail nie drukował śmieci o nazwach plików.

pjz
źródło
tym bardziej przydatne będzie: „tail -q -f / tmp / p1 / tmp / p2 | another_command”, ponieważ będzie to wykonywane linia po linii, a przy opcji -q nie będzie drukować żadnych innych śmieci
readyblue
w przypadku niebuforowanego pliku / nazwanego potoku: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & teraz / tmp / p3 można nawet nazwać potokiem i możesz go odczytać po prostu tail -f /tmp/p3wszystko to jest NIEBUDOWANE = linia po linii jest jednak niewielki rodzaj błędu. pierwszy plik / nazwany potok musi zostać zainicjowany jako pierwszy, aby ogon zaakceptował wyjście z drugiego. więc będziesz musiał echo -n > /tmp/p1i wszystko będzie działać płynnie.
readyblue
1

Najlepszym programem do tego jest lmerge. W przeciwieństwie do odpowiedzi Freiharta jest zorientowana liniowo, więc dane wyjściowe dwóch poleceń nie będą się wzajemnie blokować. W przeciwieństwie do innych rozwiązań sprawiedliwie łączy dane wejściowe, więc żadne polecenie nie może zdominować wyniku. Na przykład:

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

Daje wynik:

foo
bar
foo
bar
Rian Hunter
źródło