Bagaimana cara saya menggabungkan dua pipa bernama ke aliran input tunggal di linux

64

Menggunakan fitur pipa ( |) di Linux saya dapat meneruskan rangkaian input standar ke satu atau beberapa aliran keluaran.

Saya dapat menggunakan teeuntuk membagi output untuk memisahkan sub proses.

Apakah ada perintah untuk bergabung dengan dua aliran input?

Bagaimana saya melakukannya? Bagaimana cara kerja diff?

Cristian Ciupitu
sumber

Jawaban:

105

Secara pribadi, favorit saya (memerlukan bash dan hal-hal lain yang standar pada kebanyakan distribusi Linux)

Detailnya dapat sangat bergantung pada apa yang dihasilkan dua hal dan bagaimana Anda ingin menggabungkannya ...

Isi command1 dan command2 setelah satu sama lain di output:

cat <(command1) <(command2) > outputfile

Atau jika kedua perintah mengeluarkan versi alternatif dari data yang sama yang ingin Anda lihat berdampingan (saya telah menggunakan ini dengan snmpwalk; angka di satu sisi dan nama MIB di sisi lain):

paste <(command1) <(command2) > outputfile

Atau jika Anda ingin membandingkan output dari dua perintah yang sama (katakanlah temukan pada dua direktori yang berbeda)

diff <(command1) <(command2) > outputfile

Atau jika mereka dipesan output dari beberapa jenis, gabungkan mereka:

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

Atau jalankan kedua perintah sekaligus (meskipun bisa sedikit berebut):

cat <(command1 & command2) > outputfile

Operator <() mengatur pipa bernama (atau / dev / fd) untuk setiap perintah, memipis output dari perintah itu ke pipa bernama (atau / dev / fd file menangani rujukan) dan meneruskan nama pada baris perintah. Ada yang setara dengan> (). Anda dapat melakukan: command0 | tee >(command1) >(command2) >(command3) | command4untuk secara bersamaan mengirim output dari satu perintah ke 4 perintah lainnya, misalnya.

freiheit
sumber
luar biasa! Saya telah membaca halaman manual bash banyak waktu tetapi tidak memilih yang itu
Javier
2
Anda dapat menemukan referensi di [panduan skrip bash lanjutan] ( tldp.org/LDP/abs/html/process-sub.html ) di proyek dokumentasi linux
brice
3
saya mampu mencegah garis-garis interleaved dengan pipa melalui grep --line-buffered- berguna untuk merangkap grep'ing taildari beberapa file log. lihat stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO
16

Anda dapat menambahkan dua steam ke yang lain dengan cat, seperti yang ditunjukkan gorila.

Anda juga dapat membuat FIFO, mengarahkan output dari perintah itu, lalu membaca dari FIFO dengan program lain apa pun:

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

Sangat berguna untuk program yang hanya akan menulis atau membaca file, atau mencampur program yang hanya menghasilkan stdout / file dengan yang hanya mendukung yang lain.

Chris S
sumber
2
Yang ini bekerja pada pfSense (FreeBSD) sedangkan jawaban yang diterima tidak. Terima kasih!
Nathan
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1dan /tmp/p2pipa input Anda, sedangkan /tmp/outputoutput.

gorila
sumber
6
Catatan: Kecuali jika kedua perintah di samping ()flush output mereka di setiap baris (dan beberapa aturan POSIX lain untuk atomicity), Anda bisa berakhir dengan beberapa pengacakan aneh pada input ke cat ...
freiheit
Jika Anda tidak menggunakan titik koma alih-alih karakter ampersand?
Samir
ini adalah Epic stuff
Mobigital
5

Saya telah membuat program khusus untuk ini: fdlinecombine

Bunyinya banyak pipa (biasanya keluaran program) dan menulisnya ke stdout linewise (Anda juga dapat mengganti pemisah)

Vi.
sumber
Berfungsi sebagai iklan. Terima kasih telah mengumumkannya kepada publik.
alexei
3

Perintah yang sangat keren yang saya gunakan untuk ini adalah tpipe, Anda mungkin perlu mengkompilasi karena itu tidak umum. Benar-benar hebat untuk melakukan persis apa yang Anda bicarakan, dan sangat bersih sehingga saya biasanya menginstalnya. Halaman manualnya terletak di sini http://linux.die.net/man/1/tpipe . Unduhan yang saat ini tercantum ada di arsip ini http://www.eurogaran.com/downloads/tpipe/ .

Ini digunakan seperti ini,

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

Hati-hati di sini; hanya dengan menekannya akan berakhir dengan mencampurkan hasil dengan cara yang mungkin tidak Anda inginkan: misalnya, jika mereka mencatat file, Anda mungkin tidak benar-benar menginginkan satu baris dari satu dimasukkan setengah jalan melalui satu baris dari yang lainnya. Jika tidak apa-apa, maka

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

akan bekerja. Jika itu tidak apa - apa, maka Anda harus menemukan sesuatu yang akan melakukan buffering baris dan hanya menghasilkan baris lengkap. Syslog melakukan ini, tapi saya tidak yakin apa lagi yang bisa dilakukan.

EDIT: optimalisasi untuk bacaan tanpa basa dan pipa bernama:

mempertimbangkan / tmp / p1, / ​​tmp / p2, / tmp / p3 sebagai pipa bernama, dibuat oleh "mkfifo / tmp / p N "

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

sekarang dengan cara ini, kita dapat membaca Keluaran pipa bernama "/ tmp / p3" unbuffered oleh:

tail -f / tmp / p3

ada bug jenis kecil, Anda perlu "menginisialisasi" pipa input 1 / tmp / p1 dengan:

echo -n> / tmp / p1

agar tail akan menerima input dari pipa ke-2 / tmp / p2 terlebih dahulu dan tidak menunggu sampai sesuatu datang ke / tmp / p1. ini mungkin tidak terjadi, jika Anda yakin, / tmp / p1 akan menerima input terlebih dahulu.

Juga opsi -q diperlukan agar tail tidak mencetak sampah tentang nama file.

pjz
sumber
yang lebih bermanfaat adalah: "tail -q -f / tmp / p1 / tmp / p2 | another_command" karena akan dilakukan baris demi baris dan dengan opsi -q tidak akan mencetak sampah lain
readyblue
untuk unbuffered file / bernama pipe use: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & sekarang / tmp / p3 bahkan bisa dinamai pipe dan Anda bisa membacanya dengan mudah, tail -f /tmp/p3semua ini TIDAK DIBACAAN = baris demi baris namun ada sedikit bug jenis. file pertama / pipa bernama harus diinisialisasi terlebih dahulu agar ekor akan menerima output dari ke-2. jadi Anda harus echo -n > /tmp/p1dan semuanya akan bekerja dengan lancar.
readyblue
1

Program terbaik untuk melakukan ini adalah lmerge. Tidak seperti jawaban freihart itu berorientasi garis sehingga output dari dua perintah tidak akan saling berkelahi. Tidak seperti solusi lain, itu cukup menggabungkan input sehingga tidak ada perintah yang dapat mendominasi output. Sebagai contoh:

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

Memberikan output:

foo
bar
foo
bar
Rian Hunter
sumber