Semua orang tahu bagaimana membuat pipa searah antara dua program (mengikat stdout
dari yang pertama dan stdin
satu detik): first | second
.
Tetapi bagaimana cara membuat pipa dua arah, yaitu cross-bind stdin
dan stdout
dua program? Apakah ada cara mudah untuk melakukannya di shell?
Yah, itu cukup "mudah" dengan pipa bernama (
mkfifo
). Saya memberi tanda kutip dengan mudah karena kecuali program dirancang untuk ini, kebuntuan mungkin terjadi.Sekarang, biasanya ada buffering yang terlibat dalam penulisan stdout. Jadi, misalnya, jika kedua program tersebut adalah:
Anda akan mengharapkan loop tak terbatas. Namun sebaliknya, keduanya akan menemui jalan buntu; Anda perlu menambahkan
$| = 1
(atau setara) untuk mematikan buffering output. Kebuntuan disebabkan karena kedua program sedang menunggu sesuatu di stdin, tetapi mereka tidak melihatnya karena duduk di buffer stdout dari program lain, dan belum ditulis ke pipa.Pembaruan : memasukkan saran dari Stéphane Charzelas dan Joost:
melakukan hal yang sama, lebih pendek, dan lebih portabel.
sumber
prog1 < fifo | prog2 > fifo
.prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.prog2 < fifo0 > fifo1
, Anda dapat menghindari tarian kecil Anda denganexec 30< ...
(yang omong-omong hanya bekerja denganbash
atauyash
untuk fds lebih dari 10 seperti itu).dash
tampaknya baik-baik saja (tetapi berperilaku sedikit berbeda)Saya tidak yakin apakah ini yang ingin Anda lakukan:
Ini dimulai dengan membuka soket pendengaran pada port 8096, dan sekali koneksi dibuat, memunculkan program
second
dengan itustdin
sebagai output stream danstdout
sebagai input stream.Kemudian, yang kedua
nc
diluncurkan yang menghubungkan ke port mendengarkan dan memunculkan programfirst
denganstdout
sebagai input stream danstdin
sebagai output stream.Ini tidak sepenuhnya dilakukan menggunakan pipa, tetapi tampaknya melakukan apa yang Anda butuhkan.
Karena ini menggunakan jaringan, ini dapat dilakukan pada 2 komputer jarak jauh. Ini hampir seperti cara server web (
second
) dan browser web (first
) bekerja.sumber
nc -U
untuk soket domain UNIX yang hanya mengambil ruang alamat filesystem.Anda dapat menggunakan pipexec :
sumber
bash
versi 4 memilikicoproc
perintah yang memungkinkan ini dilakukan dalam murnibash
tanpa pipa bernama:Beberapa cangkang lain juga bisa melakukannya
coproc
.Di bawah ini adalah jawaban yang lebih terperinci tetapi mengaitkan tiga perintah, bukan dua, yang membuat hanya sedikit lebih menarik.
Jika Anda senang juga menggunakan
cat
danstdbuf
kemudian membangun dapat dibuat lebih mudah dimengerti.Penggunaan versi
bash
dengancat
danstdbuf
, mudah dimengerti:Catatan, harus menggunakan eval karena ekspansi variabel dalam <& $ var adalah ilegal di versio of bash 4.2.25 saya.
Versi menggunakan pure
bash
: Pecah menjadi dua bagian, luncurkan pipa pertama di bawah coproc, lalu makan siang bagian kedua, (baik perintah tunggal atau pipa) menghubungkan kembali ke yang pertama:Bukti dari konsep:
file
./prog
, hanya prog dummy untuk mengkonsumsi, menandai dan mencetak ulang baris. Menggunakan subkulit untuk menghindari masalah buffering mungkin berlebihan, bukan itu intinya di sini.file
./start_cat
Ini adalah versi yang menggunakanbash
,cat
danstdbuf
atau file
./start_part
. Ini adalah versi yang menggunakan murnibash
saja. Untuk keperluan demo saya masih menggunakanstdbuf
karena prog Anda yang sebenarnya harus berurusan dengan buffering secara internal untuk menghindari pemblokiran karena buffering.Keluaran:
Itu berhasil.
sumber
Sebuah blok bangunan yang nyaman untuk menulis pipa dua arah seperti itu adalah sesuatu yang menghubungkan stdout dan stdin dari proses saat ini bersama-sama. Mari kita menyebutnya ioloop. Setelah memanggil fungsi ini, Anda hanya perlu memulai pipa biasa:
Jika Anda tidak ingin memodifikasi deskriptor shell tingkat atas, jalankan ini dalam subkulit:
Berikut ini adalah implementasi portabel ioloop menggunakan pipa bernama:
Pipa bernama ada di sistem file hanya sebentar selama pengaturan ioloop. Fungsi ini tidak cukup POSIX karena mktemp sudah usang (dan berpotensi rentan terhadap serangan ras).
Implementasi khusus linux menggunakan / proc / mungkin yang tidak memerlukan pipa bernama, tapi saya pikir ini lebih dari cukup baik.
sumber
( : <$FIFO & )
lebih detail. Terima kasih telah memposting.mktemp
? Saya menggunakannya secara luas, dan jika alat yang lebih baru telah mengambil tempatnya, saya ingin mulai menggunakannya.Ada juga
dpipe
, "pipa dua arah", termasuk dalam paket vde2, dan termasuk dalam sistem manajemen paket distro saat ini .dpipe processA = processB
socat , alat koneksi segalanya untuk semua.
socat EXEC:Program1 EXEC:Program2
Ketika @ StéphaneChazelas mencatat dengan benar di komentar, contoh di atas adalah "bentuk dasar", ia memiliki contoh yang bagus dengan pilihan jawaban untuk pertanyaan serupa .
sumber
socat
gunakan soket alih-alih pipa (Anda dapat mengubahnya dengancommtype=pipes
). Anda mungkin ingin menambahkannofork
opsi untuk menghindari proses socat ekstra yang mendorong data antar pipa / soket. (terima kasih atas suntingan jawaban saya btw)Ada banyak jawaban bagus di sini. Jadi saya hanya ingin menambahkan sesuatu untuk bermain-main dengan mereka. Saya berasumsi
stderr
tidak diarahkan ke mana pun. Buat dua skrip (misalkan a.sh dan b.sh):Kemudian ketika Anda menghubungkannya dengan cara yang baik, Anda akan melihat di konsol:
sumber