Unix / Linux'ta borulu komutları anlama


16

İki basit programım var: Ave B. Aönce koşar sonra B"stdout" u alır Ave onu "stdin" olarak kullanır. Bir GNU / Linux işletim sistemi kullanıyorum ve bunu yapmanın mümkün olan en basit yolunun:

./A | ./B

Bu komutu tanımlamam gerekirse, bunun bir yapımcıdan ( A) girdi alan (yani okuyan ) ve bir tüketiciye ( B) yazan bir komut olduğunu söyleyebilirim . Bu doğru bir açıklama mı? Bir şey mi kaçırıyorum?



Komut değil, bash işlemiyle oluşturulan ve A işleminin ve stdin'in B olarak stdoutu olarak kullanılan bir kenerl nesnesidir. İki süreç neredeyse aynı anda başlatılır.
德里克 薯条 德里克

1
@ 炸鱼 Haklısın - çünkü çekirdek boru hattı pipefs dosya sisteminde bir nesnedir, ancak kabuğun kendisi söz konusu olduğunda - teknik olarak bu bir boru hattı komutudur
Sergiy Kolodyazhnyy

Yanıtlar:


26

Sorunuzla ilgili yanlış görünen tek şey ,

A önce koşar, sonra B A'nın stdout'unu alır

Aslında, her iki program da hemen hemen aynı anda başlatılacaktı. Herhangi bir giriş varsa Bokunmaya çalıştığında okumak için giriş kalmayıncaya kadar, bu engeller. Benzer şekilde, çıktıyı okuyan kimse yoksa A, yazıları okunana kadar bloke olur (bazıları boru tarafından arabelleğe alınır).

Bir boru hattında yer alan süreçleri senkronize eden tek şey I / O, yani boru boyunca okuma ve yazmadır. Yazma veya okuma olmazsa, iki süreç birbirinden tamamen bağımsız olarak çalışır. Biri diğerinin okumasını veya yazılmasını yoksayarsa, yoksayılan işlem SIGPIPE, diğer işlem sonlandığında bir sinyalle (yazıyorsa) engellenir ve sonunda bir dosya tarafından sonlanır veya dosya sonu koşulu (okunuyorsa) elde edilir. .

Açıklamak için deyimsel yol, A | Biki program içeren bir boru hattı olmasıdır. Birinci programdan standart çıktıda üretilen çıktı, ikinci girdi tarafından standart girdide okunabilir ("[çıktısı] A[girdi] B'ye bağlanır ). Kabuk bunun olmasını sağlamak için gerekli sıhhi tesisat yapar.

"Tüketici" ve "üretici" kelimelerini kullanmak istiyorsanız, sanırım bu da uygun

Bunların C dilinde yazılmış programlar olması önemli değildir. Bunun Linux, macOS, OpenBSD veya AIX olması önemli değildir.


2
Birden çok işlemi desteklemediği için DOS'ta geçici bir dosyaya yazmak kullanıldı.
CSM

2
@AlexVong Geçici bir dosyaya sahip örneğinizin tam olarak eşdeğer olmadığını unutmayın. Bir program bir dosyanın içeriğini aramayı seçebilir, ancak bir kanaldan gelen veriler aranamaz. Daha iyi bir examlp, mkfifoadlandırılmış bir boru oluşturmak için kullanmak , daha sonra borudan arka plan okumasında B'yi başlatmak ve sonra ona bir yazı yazmak olacaktır. Etki aynı olacağından , bu nit toplamadır .
Kusalananda

2
@AlexVong Bu makalede yapılan sadeleştirmeler onu gerçek boru hatlarından ayırıyor; paralel yürütme bir optimizasyon değil, gerçekten anlamsaldır. Kabuk boru hatlarını gören biri için monadik değerlendirme veya kompozisyonun çocuklara makul bir açıklamasıdır , ancak diğer yönde geçerli değildir. Kusalananda'nın fifo versiyonu daha yakın, ancak modelin hata yayma kısımları gerçekten önemli ve tekrarlanamıyor. (hepsi "kabuk boru hatlarında sadece fonksiyon kompozisyonu" treninde olan biri olarak söylüyorum)
Michael Homer

6
@AlexVong Hayır, bu tamamen pist dışında. Bu basit bir şeyi bile açıklayamıyor yes | sed 10q
Billy Amca

1
@ UncleBilly Örneğinize katılıyorum. Bu, Michael tarafından da paralel yürütmenin gerçekten gerekli olduğunu gösteriyor. Aksi takdirde fesih etmeyeceğiz.
Alex Vong

2

Genellikle dokümantasyonda kullanılan terim, bir veya daha fazla komuttan oluşan "ardışık düzen" dir, POSIX tanımına bakınız. Yani teknik olarak konuşursak, iki komutunuz var, kabuk için iki alt işlem (ya fork()+exec()'harici komutlar ya da alt kabuklar )

Üretici-tüketici kısmına gelince , boru hattı bu modelle tanımlanabilir, çünkü:

  • Üretici ve Tüketici sabit boyutlu arabelleği paylaşıyor ve en azından Linux ve MacOS X'te boru hattı arabelleği için sabit boyut var
  • Üretici ve Tüketici gevşek bir şekilde bağlanmış, boru hattındaki komutlar birbirlerinin varlığını bilmiyorlar ( /proc/<pid>/fddizini aktif olarak kontrol etmedikçe ).
  • Yapımcılar yazarlar stdoutve tüketiciler stdintek bir komut yürütülüyormuş gibi okurlar , yani birbirleri olmadan var olabilirler .

Burada gördüğüm fark, diğer dillerde Üretici-Tüketici'nin aksine, kabuk komutları arabelleğe alma kullanıyor ve arabellek dolduğunda stdout yazıyorlar, ancak Üretici-Tüketici'nin bu kurala uyması gerektiğine dair bir söz yok - sadece sıra dolduğunda veya atıldığında bekleyin veri (boru hattının yapmadığı başka bir şeydir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.