Borular Linux'ta nasıl çalışır?


25

Boruların Linux çekirdeğinde nasıl uygulandıklarını ve anlayışımı doğrulamak istediğimi okudum. Eğer hatalıysam, doğru açıklamayı içeren cevap seçilecektir.

  • Linux, çekirdeğe monte edilmiş pipefs adı verilen bir VFS'ye sahiptir (kullanıcı alanında değil)
  • pipefs tek bir süper bloğa sahiptir ve yan yana kendi köküne ( pipe:) monte edilir/
  • pipef'ler çoğu dosya sisteminin aksine doğrudan görüntülenemez
  • Pipefs giriş yoluyladır pipe(2)syscall
  • pipe(2)İle boru için kabuklar tarafından kullanılan syscall |(herhangi bir başka işlemden elle veya) operatörü normal bir dosya gibi hemen hemen davranır pipefs yeni bir dosya oluşturur
  • Boru operatörünün sol tarafındaki dosya, boru stdouthatlarında oluşturulan geçici dosyaya yönlendirildi.
  • Boru operatörünün sağ tarafındaki stdindosya, boruların üzerindeki dosyaya ayarlanmıştır.
  • pipefs bellekte saklanır ve bazı çekirdek sihir sayesinde disk belleği kullanılmamalıdır.

Bu, boruların (örneğin ls -la | less) nasıl çalıştığını açıklıyor mu?

Anlamadığım bir şey, bash gibi bir şeyin nasıl bir süreç yaratacağıdır ' stdinya da stdoutdöndüren dosya tanımlayıcısına pipe(2). Bununla ilgili henüz bir şey bulamadım.


Aynı adda iki farklı katmandan bahsettiğinizi unutmayın. pipe()Çekirdek çağrısı, onu destekleyen makinelerle ( pipefs, vb.) Birlikte |, kabuğunuzda sunulan operatörden çok daha düşük bir seviyededir . Sonuncusu genellikle eskisi kullanılarak uygulanır, ancak olması gerekmez.
Greg Hewgill,

Evet, özellikle |operatörün sadece pipe(2)bash gibi bir işlem olarak çağırdığı varsayımıyla düşük seviyeli işlemlere atıfta bulunuyorum .
Brandon Wamboldt

Yanıtlar:


19

Şimdiye kadarki analizlerin genelde doğru. Bir kabuğun bir işlemin stdin'ini bir boru tanımlayıcısına ayarlaması (pseudocode) olabilir:

pipe(p) // create a new pipe with two handles p[0] and p[1]
fork() // spawn a child process
    close(p[0]) // close the write end of the pipe in the child
    dup2(p[1], 0) // duplicate the pipe descriptor on top of fd 0 (stdin)
    close(p[1]) // close the other pipe descriptor
    exec() // run a new process with the new descriptors in place

Teşekkürler! dup2Çağrıya neden ihtiyaç duyulduğunu merak ediyorum ve doğrudan boru tanımlayıcısını stdin'e atayamıyor musunuz?
Brandon Wamboldt

3
Arayan, dosya tanımlayıcısının sayısal değerinin oluşturulduğu sırada ne olacağını seçemez pipe(). dup2()Çağrı Arayan (gerekli 0, 1, 2, stdin'i edilir, stdout stderr için) belirli bir sayısal değere dosya tanımlayıcısı kopyalamak için izin verir. Bu, "doğrudan stdin'e atama" nın çekirdek eşdeğeridir. C çalışma zamanı kitaplığı global değişkeninin çekirdekle ilgili olmayan stdinbir a FILE *olduğunu unutmayın (tanımlayıcı 0'a bağlanması başlatılsa da).
Greg Hewgill,

Mükemmel cevap! Ayrıntılarda biraz kayboldum. Sadece exec () komutunu çalıştırmadan önce neden kapattığınızı (p [1]) merak ediyorsunuz? Dup2 geri döndüğünde, p [1] fd 0'a işaret etmez mi? Sonra kapat (p [1]), dosya tanımlayıcısını 0 kapatır. Öyleyse, alt sürecin başından nasıl okuyabiliriz?
kullanıcı1559897

@ user1559897: dup2Çağrı değişmiyor p[1]. Bunun yerine, iki adet kulbu yapar p[1]ve 0aynı çekirdek nesnesi (boru) 'ın. Çocuk sürecinin iki stdin tutamağına ihtiyacı olmadığından (ve ne de olsa numaralı tutamacın ne olduğunu bilmediğinden p[1]), p[1]daha önce kapatıldı exec.
Greg Hewgill

@GregHewgill Gotchu. Teşekkürler!
user1559897
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.