Memahami perintah pipa di Unix / Linux


16

Saya punya dua program sederhana: Adan B. Aakan berjalan terlebih dahulu, kemudian Bmendapatkan "stdout" Adan menggunakannya sebagai "stdin". Asumsikan saya menggunakan sistem operasi GNU / Linux dan cara paling sederhana untuk melakukan ini adalah:

./A | ./B

Jika saya harus menggambarkan perintah ini, saya akan mengatakan bahwa itu adalah perintah yang mengambil input (yaitu, dibaca) dari produsen ( A) dan menulis ke konsumen ( B). Apakah itu deskripsi yang benar? Apakah saya kehilangan sesuatu?



Ini bukan perintah, ini adalah objek kenerl yang dibuat oleh proses bash, yang digunakan sebagai stdout dari proses A dan stdin sebagai B. Dua proses dimulai hampir bersamaan.
炸鱼 薯条 德里克

1
@ 炸鱼 Anda benar - karena pipeline kernel adalah objek di filesystem pipefs, tetapi sejauh menyangkut shell - secara teknis itu adalah perintah pipeline
Sergiy Kolodyazhnyy

Jawaban:


26

Satu-satunya hal tentang pertanyaan Anda yang salah adalah yang Anda katakan

A akan berjalan lebih dulu, lalu B mendapat stdout dari A

Faktanya, kedua program akan dimulai pada waktu yang hampir bersamaan. Jika tidak ada input Bketika mencoba membaca, itu akan memblokir sampai ada input untuk dibaca. Demikian juga, jika tidak ada yang membaca output dari A, maka penulisan akan memblokir sampai outputnya dibaca (beberapa akan buffered oleh pipa).

Satu-satunya hal yang menyinkronkan proses yang mengambil bagian dalam pipa adalah I / O, yaitu membaca dan menulis melintasi pipa. Jika tidak ada penulisan atau pembacaan terjadi, maka kedua proses akan berjalan sepenuhnya independen satu sama lain. Jika salah satu mengabaikan pembacaan atau penulisan yang lain, proses yang diabaikan akan memblokir dan akhirnya dibunuh oleh SIGPIPEsinyal (jika menulis) atau mendapatkan kondisi file pada aliran input standar (jika membaca) ketika proses lain berakhir .

Cara idiomatis untuk menggambarkan A | Badalah bahwa itu adalah pipa yang mengandung dua program. Output yang dihasilkan pada output standar dari program pertama tersedia untuk dibaca pada input standar oleh yang kedua ("[output] Adisalurkan ke [input] B"). Shell melakukan plumbing yang diperlukan untuk memungkinkan hal ini terjadi.

Jika Anda ingin menggunakan kata "konsumen" dan "produsen", saya rasa itu juga tidak masalah.

Fakta bahwa ini adalah program yang ditulis dalam C tidak relevan. Fakta bahwa ini adalah Linux, macOS, OpenBSD atau AIX tidak relevan.


2
Menulis ke file sementara digunakan di DOS, karena itu tidak mendukung banyak proses.
CSM

2
@AlexVong Perhatikan bahwa contoh Anda dengan file sementara tidak persis sama. Suatu program dapat memilih untuk mencari isi suatu file, tetapi data yang keluar dari suatu pipa tidak dapat dicari. Examlp yang lebih baik akan digunakan mkfifountuk membuat pipa bernama, kemudian mulai B di latar belakang membaca dari pipa, dan kemudian menulis untuk itu. Ini adalah nit-picking, karena efeknya akan sama.
Kusalananda

2
@AlexVong Penyederhanaan yang dibuat dalam artikel itu menceraikannya dari saluran pipa nyata; eksekusi paralelnya benar-benar semantik, bukan optimasi. Ini merupakan penjelasan bohong-ke-anak yang masuk akal mengenai evaluasi atau komposisi monadik untuk seseorang yang melihat jaringan pipa shell, tetapi itu tidak valid ke arah lain. Versi fifo Kusalananda lebih dekat, tetapi bagian propagasi kesalahan dari model itu benar-benar penting dan tidak dapat ditiru. (yang semuanya saya katakan sebagai seseorang yang sangat di kereta "jaringan pipa shell hanya komposisi fungsi")
Michael Homer

6
@AlexVong Tidak, itu benar - benar keluar jalur. Itu bahkan tidak dapat menjelaskan sesuatu yang sederhana seperti yes | sed 10q
Paman Billy

1
@UncleBilly Saya setuju dengan contoh Anda. Ini menunjukkan bahwa eksekusi paralel benar-benar diperlukan juga dicatat oleh Michael. Kalau tidak, kita akan mendapatkan non-terminasi.
Alex Vong

2

Istilah yang biasanya digunakan dalam dokumentasi adalah "pipeline", yang terdiri dari satu atau lebih perintah, lihat definisi POSIX. Jadi secara teknis, itu adalah dua perintah yang Anda miliki di sana, dua subproses untuk shell (baik fork()+exec()perintah eksternal atau subkulit).

Sedangkan untuk bagian produsen-konsumen , pipa dapat dijelaskan dengan pola itu, karena:

  • Produser dan Konsumen berbagi buffer ukuran tetap, dan setidaknya di Linux dan MacOS X, ada ukuran tetap untuk buffer saluran pipa
  • Produser dan Konsumen secara longgar digabungkan, perintah dalam pipa tidak mengetahui keberadaan satu sama lain (kecuali mereka secara aktif memeriksa /proc/<pid>/fddirektori).
  • Produsen menulis stdoutdan konsumen membaca stdinseolah-olah mereka adalah perintah tunggal yang dieksekusi, alias mereka dapat hidup tanpa satu sama lain .

Perbedaan yang saya lihat di sini adalah bahwa tidak seperti Produser-Konsumen di bahasa lain, perintah shell menggunakan buffering dan mereka menulis stdout setelah buffer diisi, tetapi tidak ada menyebutkan bahwa Konsumen-Konsumen harus mengikuti aturan itu - hanya menunggu ketika antrian diisi atau dibuang data (yang merupakan hal lain yang tidak dilakukan pipa).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.