เปลือกทั่วไป“ ส้อมระเบิด” เรียกตัวเองว่าสองครั้งอย่างแน่นอนอย่างไร?


15

หลังจากผ่านคำถาม Fork Bombที่โด่งดังใน Askubuntu และเว็บไซต์แลกเปลี่ยนเงินตราต่างประเทศอื่น ๆ ฉันไม่เข้าใจว่าสิ่งที่ทุกคนพูดถึงมันชัดเจน

คำตอบมากมาย ( ตัวอย่างที่ดีที่สุด ) พูดอย่างนี้:

" {:|: &}หมายถึงเรียกใช้ฟังก์ชัน:และส่งออกไปยัง:ฟังก์ชันอีกครั้ง"

ดีสิ่งที่แน่นอนคือการส่งออกของ:? สิ่งที่ถูกส่งผ่านไปยังอีก:หรือไม่

และนอกจากนี้ยังมี:

โดยพื้นฐานแล้วคุณกำลังสร้างฟังก์ชั่นที่เรียกตัวเองว่าสองครั้งทุกการโทรและไม่มีทางที่จะยุติตัวเอง

วิธีการที่ถูกดำเนินการสองครั้งว่า? ในความคิดของฉันไม่มีอะไรถูกส่งผ่านไปยังวินาที:จนกว่าการดำเนินการครั้งแรกจะ:เสร็จสิ้นซึ่งจริงๆแล้วจะไม่มีวันสิ้นสุด

ในCตัวอย่างเช่น

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

ที่สองfoo()ไม่ได้ดำเนินการเลยเพียงเพราะครั้งแรกfoo()ไม่สิ้นสุด

ฉันคิดว่าตรรกะเดียวกันนี้ใช้ได้กับ:(){ :|: & };:และ

:(){ : & };:

ทำงานเช่นเดียวกับ

:(){ :|: & };:

โปรดช่วยฉันเข้าใจตรรกะ


9
คำสั่งในไพพ์ไลน์ทำงานแบบขนานโดย:|:ที่สอง:ไม่จำเป็นต้องรอคำสั่งแรกเสร็จสมบูรณ์
cuonglm

คำตอบ:


26

การวางท่อไม่จำเป็นต้องให้อินสแตนซ์แรกเสร็จสิ้นก่อนที่อีกอันหนึ่งจะเริ่มทำงาน ที่จริงแล้วสิ่งที่ทำจริงๆคือการเปลี่ยนstdoutของอินสแตนซ์แรกไปยังstdinของอันที่สองดังนั้นพวกเขาจึงสามารถทำงานพร้อมกันได้ (เนื่องจากต้องใช้ fork fork เพื่อทำงาน)

เอาท์พุทของ:คืออะไร? สิ่งที่ถูกส่งผ่านไปยังอีก:หรือไม่

':' ไม่ได้เขียนอะไรไปยังอินสแตนซ์อื่น ':' มันแค่เปลี่ยนเส้นทางstdoutไปยังstdinของอินสแตนซ์ที่สอง ถ้ามันเขียนอะไรบางอย่างระหว่างการประหารชีวิต (ซึ่งมันไม่เคยจะทำได้เพราะมันไม่ทำอะไรนอกจากการฟอร์กตัวเอง) มันจะไปที่stdinของอินสแตนซ์อื่น

มันช่วยให้จินตนาการถึงstdinและstdoutเป็นกอง:

สิ่งใดก็ตามที่เขียนไปยังstdinจะถูกซ้อนขึ้นเมื่อโปรแกรมตัดสินใจอ่านจากนั้นในขณะที่stdoutทำงานในลักษณะเดียวกัน: กองที่คุณสามารถเขียนได้ดังนั้นโปรแกรมอื่น ๆ สามารถอ่านได้เมื่อต้องการ

ด้วยวิธีนี้มันง่ายที่จะจินตนาการถึงสถานการณ์เช่นไพพ์ที่ไม่มีการสื่อสารเกิดขึ้น (สองกองว่างเปล่า) หรือการเขียนและอ่านที่ไม่ซิงโครไนซ์

วิธีการที่ถูกดำเนินการสองครั้งว่า? ในความคิดของฉันไม่มีอะไรถูกส่งผ่านไปยังวินาที:จนกว่าการดำเนินการครั้งแรกจะ:เสร็จสิ้นซึ่งจริงๆแล้วจะไม่มีวันสิ้นสุด

เนื่องจากเราเพิ่งจะเปลี่ยนทิศทางอินพุทและเอาท์พุทของอินสแตนซ์ดังนั้นจึงไม่มีข้อกำหนดสำหรับอินสแตนซ์แรกที่จะเสร็จสิ้นก่อนที่อินสแตนซ์ที่สองจะเริ่มต้นขึ้น โดยปกติแล้วมันต้องการให้ทั้งสองทำงานพร้อมกันเพื่อที่สองสามารถทำงานกับข้อมูลที่ถูกแยกวิเคราะห์โดยอันแรกได้ทันที นั่นคือสิ่งที่เกิดขึ้นที่นี่ทั้งคู่จะถูกเรียกโดยไม่ต้องรอให้เสร็จก่อน ที่ใช้กับบรรทัดคำสั่งของchain chainsทั้งหมด

ฉันคิดว่าตรรกะเดียวกันนี้ใช้ได้กับ: () {: |: &} ;: และ

:(){ : & };:

ทำงานเช่นเดียวกับ

:(){ :|: & };:

ตัวแรกไม่ทำงานเพราะถึงแม้ว่ามันจะเรียกใช้ซ้ำตัวเองฟังก์ชันจะถูกเรียกในพื้นหลัง ( : &) คนแรก:ไม่รอจนกว่า "เด็ก" :จะกลับมาก่อนที่จะจบตัวเองดังนั้นในที่สุดคุณอาจมีเพียงหนึ่งตัวอย่างของการ:ทำงาน หากคุณมี:(){ : };:มันจะทำงานแม้ว่าตั้งแต่แรก:จะรอให้ "ลูก" :กลับมาซึ่งจะรอ "ลูก" ของตัวเอง:เพื่อกลับไปและอื่น ๆ

ต่อไปนี้เป็นคำสั่งต่าง ๆ ที่มีลักษณะเป็นจำนวนอินสแตนซ์ที่กำลังทำงาน:

:(){ : & };:

1 อินสแตนซ์ (การโทร:และการออก) -> 1 อินสแตนซ์ (การโทร:และการออก) -> 1 อินสแตนซ์ (การโทร:และการปิด) -> 1 อินสแตนซ์ -> ...

:(){ :|: &};:

1 อินสแตนซ์ (เรียก 2 :และออกจาก) -> 2 อินสแตนซ์ (แต่ละคนโทร 2 :และออกจาก) -> 4 อินสแตนซ์ (แต่ละคนเรียก 2 :และออกจาก) -> 8 อินสแตนซ์ -> ...

:(){ : };:

1 อินสแตนซ์ (เรียก:และรอให้มันส่งคืน) -> 2 อินสแตนซ์ (เด็กโทรอีกครั้ง:และรอให้ส่งคืน) -> 3 อินสแตนซ์ (เด็กโทรอีกครั้ง:และรอให้มันส่งคืน) -> 4 อินสแตนซ์ -> ...

:(){ :|: };:

1 อินสแตนซ์ (โทร 2 :และรอให้พวกเขากลับมา) -> 3 อินสแตนซ์ (เด็ก ๆ โทรหา 2 :คนและรอให้พวกเขากลับมา) -> 7 อินสแตนซ์ (เด็กโทรหา 2 :คนแต่ละคนและรอให้พวกเขากลับมา) -> 15 ครั้ง -> ...

อย่างที่คุณเห็นการเรียกใช้ฟังก์ชั่นในพื้นหลัง (โดยใช้&) ช้าลงในการวางระเบิดเนื่องจากผู้เรียกจะออกจากกันก่อนที่ฟังก์ชันที่เรียกใช้จะกลับมา


คำถาม. จะ:(){ : & && : &}; :ใช้เป็นส้อมระเบิดได้หรือไม่? คุณจะเพิ่มทวีคูณและในความเป็นจริงคุณสามารถใส่หลาย ๆ อัน: &ในนั้นเพื่อเพิ่มได้เร็วขึ้น
JFA

@JFA `─> $: () {: & &&: &}; bash: syntax error near unexpected token &&' `ให้ข้อผิดพลาดทางไวยากรณ์ คุณสามารถทำสิ่งนี้: :(){ $(: &) && $(: &)}; :แต่อีกครั้งซึ่งแตกต่างจากไปป์ไลน์ที่จะไม่ทำงานขนาน :(){: & };:ซึ่งก็จะเทียบเท่า ต้องการยืนยันไหม ลองสิ่งเหล่านี้time $( $(sleep 1 & ) && $(sleep 1 &) )และนี่time $(sleep 1 | sleep 1)
Severus Tux

ตรง:(){ $(: &) && $(: &)};นั้นเป็นฟังก์ชั่นที่จะออกตรรกะและการดำเนินงานในค่าตอบแทนของอินสแตนซ์ที่หนึ่งและสอง ปัญหาคือเนื่องจากตรรกะและเป็นจริงเฉพาะถ้าทั้งสองค่าเป็นจริงเพื่อประสิทธิภาพเฉพาะอินสแตนซ์แรกจะถูกเรียกใช้ ถ้าค่าส่งคืนเป็น 1 อินสแตนซ์ที่สองจะทำงาน หากคุณต้องการทำให้การทิ้งระเบิดเร็วยิ่งขึ้นฉันคิดว่าคุณสามารถเพิ่มอินสแตนซ์ในห่วงโซ่ได้มากขึ้นเช่น:(){ :|:|: &}; :
IanC

เช่นเดียวกับบันทึกด้านข้างสคริปต์จำนวนมากใช้ลักษณะการทำงานของ AND ในสถานการณ์ต่อไปนี้: สมมติว่าคุณต้องการรัน prog2 หาก prog1 ส่งคืนจริง (ซึ่งใน bash คือ 0) แทนที่จะทำคำสั่ง if ( if [ prog1 ]; then; prog2; fi) คุณสามารถเขียน ( prog1 && prog2) และ prog2 จะทำงานก็ต่อเมื่อค่าส่งคืนของ prog1 เป็นจริง
IanC

ตกลงเหล่านี้เป็นจุดที่ดีทั้งหมด ฉันใช้&&โทรapt-get update && apt-get upgradeและ&ที่ท้ายบรรทัดเพื่อให้ทำงานในพื้นหลัง แต่นั่นเป็นจุดที่ดีที่พวกเขาจะไม่ทำงานร่วมกัน เครื่องหมายอัฒภาคไม่ทำงานกับเครื่องหมายแอมเปอร์แซนด์
JFA
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.