Neden bash boru hatlarında * "evet" kullanmak * sonsuz döngülere neden olmaz?


16

Belgelerine göre, bash bir boru hattındaki tüm komutların devam etmeden önce bitmesini bekler

Kabuk, bir değer döndürmeden önce boru hattındaki tüm komutların sonlanmasını bekler.

Peki komut neden yes | truehemen bitiyor? yesDöngü sonsuza kadar olmamalı ve boru hattının asla geri dönmemesine neden olmalı mı ?


Ve bir alt sorgu: POSIX spesifikasyonuna göre , kabuk boru hatları ya son komut bittikten sonra geri dönmeyi seçebilir ya da tüm komutlar bitene kadar bekleyebilir. Yaygın mermilerin bu anlamda farklı davranışları var mı? yes | trueSonsuza dek dönecek mermiler var mı?


yes | tee >(true) >/dev/nullbeklediğiniz gibi yapacak, btw, teetüm yazarlar ölene kadar devam trueedecek , bu yüzden çıkmak onu tamamen bozmayacak.
Charles Duffy

1
truetemelde bir {return 0;}programdır, bu yüzden sonsuza dek uzun süre çalışmasını beklemezdim.
Dmitry Grigoryev

Yanıtlar:


33

Ne zaman trueçıkışlar, borunun okuma tarafı kapalı, ancak yesyazma tarafına yazmaya çalışırken devam eder. Bu duruma "kırık boru" denir ve çekirdeğin SIGPIPEsinyal göndermesine neden olur yes. Yana yesbu sinyalin hakkında hiçbir şey special yapıyor, o öldürülecek. Sinyali yoksayarsa, writehata kodu ile çağrısı başarısız olur EPIPE. Bunu yapan programlar EPIPEyazmayı fark etmeye ve durdurmaya hazır olmalıdır , yoksa sonsuz bir döngüye girerler.

Bunu yaparsanız strace yes | true1 her iki olasılık için hazırlık çekirdeği görebilirsiniz:

write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17556, si_uid=1000} ---
+++ killed by SIGPIPE +++

stracehata ayıklayıcı API'sı aracılığıyla olayları izliyor. Gönderen yesbireyin perspektifinden olsa da, sinyal ilk olmuyor. (Teknik olarak, sinyal çekirdeği kontrolü kullanıcı alanına döndürdükten sonra verilir, ancak daha fazla makine talimatı yürütülmeden önce write, C kütüphanesindeki "sarmalayıcı" işlevinin ayarlanması errnove uygulamaya geri dönme şansı yoktur .)


1 Ne yazık ki straceLinux'a özgüdür. Çoğu modern Unixler sahip bazı benzer bir şey yapar komutu, ancak genellikle, farklı bir isme sahip muhtemelen iyice olarak değil kod çözme syscall argümanlar yapar ve bazen sadece root için çalışır.


3
@hugomg bu durumda, boru tamamen ilgisizdir.
muru

3
@hugomg çünkü hiçbir şey yesboruya bağlı değil.
muru

4
Bu, "boru hattını sonlandırmadan önce tüm komutlar bitene kadar bekleyin" belgelenmiş davranışının bir göstergesidir. yesYazdığı FD bir boruya bağlı olmadığından SIGPIPE almayı engeller .
Tom Hunt

2
@hugomg, sonsuza dek yes >/dev/nullilmek gibi sonsuza dek ilmek yapıyor. Basit komutlar için de geçerli olmayan boru hatları hakkında hiçbir şey göstermez (Tom'un belirttiği gibi, fesih beklemek davranışı basit komutlar için de geçerlidir).
Charles Duffy

2
@zwol: Sanırım terimlerimizi burada biraz farklı anlamlarla kullanıyoruz ya da biraz farklı perspektiflerden bir şeyler düşünüyoruz… ancak her iki durumda da write()(libc'deki işlev) sonrasına kadar geri dönmez (kontrolü PC'ye aktarma) sinyal işleyici çalışmıştır, ancak sinyal işleyici programı sonlandırdığından, kontrol hiçbir zaman aktarılmaz ve bu nedenle write()geri dönmez. Evet, çekirdeğe bazı xxx_write()işlevlerin geri dönmesini sağlayarak uygulandı -EPIPE, ancak bir kullanıcı-uzay programında hata ayıklıyoruz ve bununla ilgilenmiyoruz.
Dietrich Epp

5

Evet mermisi var mı? gerçek sonsuza kadar döngü olacak?

Muhtemel beri yeskomut boru kullanıyor ve boru bozuldu zaman başarısız olur. sleepÖte yandan, boruyu kullanmaz, bu yüzden:

sleep 100000000 | true

en azından 100000000 saniye boyunca çalışır.


2
Bir borudaki son (en sağdaki) yerleşik komut için ve trueyerleşik olan nerede çatallanmayan tüm modern mermilere dikkat edin . Bu son sürümlerinde için geçerlidir Bourne Shell, ksh93, zsh. ^ZBöyle bir komut çalışırken vurursanız , uyku uykusunu askıya alır ve dış yardım olmadan kabuk hiçbir zaman kurtarılamaz.
schily

3
zsh 4.3.4 (i386-pc-solaris2.11) burada, bu son zamanlarda değiştirilmiş gibi görünüyor. İlginç bir fikir, Bourne Kabuğu için benzer bir düzeltme uygulayıp uygulayamayacağımıza bakmam gerekecek. Hala nasıl çalıştığı ve Bourne Kabuğu'nda olduğu gibi hangi tty işlem grubunun kullanıldığı sorusu var.
schily

2
@CharlesDuffy anladığım kadarıyla, modern kabuklardan iyileştirmeleri geri aldığı bir sh sürümünü koruyor. Burada, bir yerlerde yayınladı.
muru

3
Yadigarı arşivlerindeki Bourne Kabuğu ~ 2007'ye kadar sürdürüldü, ancak hala çağrı içerdiği için hiçbir zaman tamamen taşınabilir hale getirilmedi sbrk(). Taşınabilir ve bakımı yapılmış bir sürüm, schily araçları paketindedir ve @Charles Duffy, bilgi için bir yer keşfetti ;-)
schily

2
muru Bourne Kabuğuna desteklediğim özelliklerin çoğu benim bsh(UNOS'un ilk sanal sürümü olan UNOS'un sanal bellek gelişmiş versiyonu olan VBERTOS'tan Berthold Shell). Bsh 1984 ve 1985'te birçok csh özelliği elde etti, ancak UNOS'un takma mekanizması 1980'de csh'den daha üstüntü. Diğer yeni Bourne Shell özellikleri POSIX'e uygundur ve POSIX uyumluluğuna yaklaşmasını sağlar.
schily
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.