Tipik mermi “çatal bombası” tam olarak nasıl iki kere çağırır?


15

Askubuntu ve diğer pek çok Stack Exchange sitesinde Çatal Bomba ile ilgili ünlü soruları inceledikten sonra , herkesin söylediklerini açıkça anlayamıyorum.

Birçok cevap ( En iyi örnek ) bunu söylüyor:

" {:|: &}fonksiyonu çalıştırmak :ve çıktısını :tekrar fonksiyona göndermek "

Peki, çıktısı tam olarak: nedir? Diğerine ne geçiyor :?

Ve ayrıca:

Esasen, her aramada iki kez kendisini çağıran ve kendisini sonlandırmak için herhangi bir yolu olmayan bir işlev oluşturuyorsunuz .

Bu tam olarak iki kez nasıl yapılır ? Benim düşünceme göre, :birincisi :idamını bitirene kadar ikincisine geçilmez, ki bu aslında hiç bitmeyecektir.

Olarak Cörneğin,

foo()
{
    foo();
    foo(); // never executed 
}

ikincisi foo()hiç yürütülmez, çünkü ilki foo()asla bitmez.

Aynı mantığın :(){ :|: & };:ve

:(){ : & };:

aynı işi yapar

:(){ :|: & };:

Lütfen mantığı anlamama yardımcı olun.


9
Boru hatlarındaki komut paralel olarak çalışır :|:, ikincisinin :ilkinin tamamlanmasını beklemesi gerekmez.
cuonglm

Yanıtlar:


26

Boru tesisatı, ilk eşgörünümün diğerinin başlamasından önce bitmesini gerektirmez. Aslında, bu da yaptığını bütün yönlendirme olduğunu stdout'u için ilk derece Stdin (bunlar işe çatal bomba için gereken gibi) bu yüzden aynı anda çalışan edilebilir ikincisinin.

Peki, çıktısı tam olarak nedir :? diğerine ne geçiyor :?

':' Diğer bir şey yazmıyor ':' örneği, sadece yönlendirme oluyor stdout'u için Stdin ikinci örneğinin. Eğer onun yürütme sırasında bir şeyler yazıyor (o asla, hangi hiçbir şey ama kendisini çatallama yapar beri) o gider Stdin diğer örneğinin.

Stdin ve stdout'u bir yığın olarak hayal etmeye yardımcı olur :

Yazılır ne olursa olsun Stdin ederken, programın ondan okumaya karar verdiğinde hazır yığılı edilecektir stdout'u aynı şekilde çalışır: Bir kazık sen yazabilir onlar istediklerinde böylece diğer programlar ondan okuyabilir.

Bu şekilde iletişim olmayan bir boru (iki boş yığın) veya senkronize olmayan yazma ve okuma gibi durumları hayal etmek kolaydır.

Bu tam olarak iki kez nasıl yapılır? Benim düşünceme göre, :birincisi :idamını bitirene kadar ikincisine geçilmez, ki bu aslında hiç bitmeyecektir.

Sadece örneklerin giriş ve çıkışını yeniden yönlendirdiğimiz için, ilk örneğin ikincisinin başlamasından önce bitirilmesine gerek yoktur. Aslında genellikle her ikisinin aynı anda çalışması istenir, böylece ikincisi birincisi tarafından anında ayrıştırılan verilerle çalışabilir. Burada olan budur, her ikisi de ilkinin bitmesini beklemeye gerek kalmadan çağrılacaktır. Bu herkes için geçerlidir boru zincirleri komut satırları .

Aynı mantığın aşağıdakiler için de geçerli olduğunu düşünüyorum: () {: |: &} ;: ve

:(){ : & };:

İle aynı işi yapar

:(){ :|: & };:

Birincisi işe yaramaz, çünkü kendini tekrar tekrar çalıştırıyor olsa da, işlev arka planda ( : &) çağrılır . Birincisi :, "çocuk" :kendisini sonlandırmadan önce geri dönmeyi beklemez , bu nedenle sonunda sadece bir tane :koşu örneğiniz olur . Eğer :(){ : };:olsaydı, işe yarayacaktı, çünkü ilk :"çocuğun" :geri dönmesini bekleyecekti, bu da kendi "çocuğunun" :geri dönmesini bekleyecekti , vb.

Kaç komutun çalışacağı açısından farklı komutların nasıl görüneceği aşağıda açıklanmıştır:

:(){ : & };:

1 örnek (aramalar :ve çıkışlar) -> 1 örnek (aramalar :ve çıkışlar) -> 1 örnek (aramalar :ve çıkışlar) -> 1 örnek -> ...

:(){ :|: &};:

1 örnek (2'nin :ve çıkışların çağrılması ) -> 2 örnek (her biri 2'nin :ve çıkışların çağrılması ) -> 4 örnek (her biri 2'nin çağırması): ve çıkıntının ) -> 8 örnek -> ...

:(){ : };:

1 örnek (çağrılar :ve geri dönmesini bekler) -> 2 örnek (çocuk başka bir çağrı :yapar ve geri dönmesini bekler) -> 3 örnek (çocuk başka bir çağrı :yapar ve geri dönmesini bekler) -> 4 örnek -> ...

:(){ :|: };:

1 örnek (2'yi çağırır :ve geri dönmelerini bekler) -> 3 örnek (çocuklar :her biri 2'yi arar ve geri dönmelerini bekler) -> 7 örnek (çocuklar :her birini 2 arar ve geri dönmelerini bekler) -> 15 örnek -> ...

Gördüğünüz gibi, fonksiyonun arka planda (kullanılarak &) çağrılması aslında çatal bombasını yavaşlatır, çünkü çağrı yapılan fonksiyonlar geri dönmeden önce çıkılacaktır.


Soru. :(){ : & && : &}; :Çatal bomba gibi de çalışır mıydı ? Üstel olarak da artarsınız ve aslında, : &daha da hızlı artırmak için oraya birden fazla tane koyabilirsiniz .
JFA

@JFA `─> $: () {: & &&: &}; : `sözdizimi hatası veriyor bash: syntax error near unexpected token &&' . Bunu yapabilirsin:, :(){ $(: &) && $(: &)}; :Ama yine, boru hattının aksine, bu paralel çalışmaz. Hangi eşdeğerdir :(){: & };:. Doğrulamak ister misiniz? Bunları deneyin time $( $(sleep 1 & ) && $(sleep 1 &) )ve butime $(sleep 1 | sleep 1)
Severus Tux

Tam olarak, :(){ $(: &) && $(: &)};birinci ve ikinci örneğin dönüş değerlerinde mantıksal bir AND işlemi veren bir işlevdir. Sorun şu ki, mantıksal bir AND yalnızca her iki değer de doğruysa doğrudur, verimlilik için yalnızca ilk örnek çalıştırılır. Dönüş değeri 1 ise, ikinci örnek çalışır. Çatal bombayı daha da hızlı yapmak istiyorsanız, zincire daha fazla örnek atabileceğinizi düşünüyorum:(){ :|:|: &}; :
IanC

Yan not olarak, birçok komut dosyası VE'nın bu davranışını aşağıdaki durumda kullanır: prog1 true değerini döndürürse prog2'yi çalıştırmak istediğinizi varsayalım (bash içinde 0'dır). Bir if-ifadesi ( if [ prog1 ]; then; prog2; fi) yapmak yerine yalnızca ( prog1 && prog2) yazabilirsiniz ve prog2 yalnızca prog1'in dönüş değeri doğru olduğunda çalışır.
IanC

Tamam, bunların hepsi harika noktalar. Kullandığım &&çağrısına apt-get update && apt-get upgradeve &birlikte çalışmaz büyük noktaya sa işte satırın sonunda arka planda çalışmasına ama. Noktalı virgül ve işareti ile çalışmaz.
JFA
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.