Làm thế nào chính xác làm thế nào vỏ bom điển hình khác ngã ba bom gọi chính nó hai lần?


15

Sau khi xem qua các câu hỏi nổi tiếng về Fork Bomb trên Askubfox và nhiều trang Stack Stack khác, tôi hoàn toàn không hiểu mọi người đang nói gì rõ ràng như vậy.

Nhiều câu trả lời ( ví dụ tốt nhất ) nói điều này:

" {:|: &}có nghĩa là chạy chức năng :và gửi lại đầu ra của nó cho :chức năng"

Chà, chính xác thì đầu ra của :cái gì? Điều gì đang được truyền cho người khác :?

Và cũng:

Về cơ bản, bạn đang tạo một hàm tự gọi hai lần mỗi cuộc gọi và không có cách nào tự chấm dứt.

Làm thế nào chính xác là thực hiện hai lần ? Theo tôi, không có gì được chuyển sang lần thứ hai :cho đến khi lần đầu tiên :kết thúc việc thực hiện, điều này thực sự sẽ không bao giờ kết thúc.

Trong Cví dụ,

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

cái thứ hai hoàn toàn foo()không được thực hiện, chỉ vì cái thứ nhất foo()không bao giờ kết thúc.

Tôi nghĩ rằng logic tương tự áp dụng cho :(){ :|: & };:

:(){ : & };:

làm công việc tương tự như

:(){ :|: & };:

Xin hãy giúp tôi hiểu logic.


9
Lệnh trong đường ống chạy song song, trong :|:, thứ hai :không cần đợi cái đầu tiên hoàn thành.
cuonglm

Câu trả lời:


26

Đường ống không yêu cầu phiên bản đầu tiên kết thúc trước khi phiên bản khác bắt đầu. Trên thực tế, tất cả những gì nó thực sự làm là chuyển hướng stdout của phiên bản đầu tiên sang stdin của phiên bản thứ hai, để chúng có thể chạy đồng thời (vì chúng phải cho bom ngã ba hoạt động).

Chà, chính xác thì đầu ra của :cái gì? những gì đang được truyền cho người khác :?

':' không viết bất cứ điều gì cho trường hợp khác ':', nó chỉ chuyển hướng thiết bị xuất chuẩn sang stdin của thể hiện thứ hai. Nếu nó viết một cái gì đó trong quá trình thực thi của nó (điều mà nó sẽ không bao giờ, vì nó không làm gì ngoài việc tự nó), nó sẽ đi đến stdin của ví dụ khác.

Nó giúp tưởng tượng stdinstdout như một đống:

Bất cứ điều gì được viết cho stdin sẽ được chất đống sẵn sàng khi chương trình quyết định đọc từ nó, trong khi thiết bị xuất chuẩn hoạt động theo cách tương tự: một đống bạn có thể viết vào, để các chương trình khác có thể đọc từ đó khi chúng muốn.

Bằng cách đó, thật dễ dàng để tưởng tượng các tình huống như một đường ống không có giao tiếp xảy ra (hai cọc trống) hoặc ghi và đọc không đồng bộ.

Làm thế nào chính xác là thực hiện hai lần? Theo tôi, không có gì được chuyển sang lần thứ hai :cho đến khi lần đầu tiên :kết thúc việc thực hiện, điều này thực sự sẽ không bao giờ kết thúc.

Vì chúng ta chỉ chuyển hướng đầu vào và đầu ra của các thể hiện, nên không có yêu cầu nào cho trường hợp đầu tiên kết thúc trước khi cái thứ hai bắt đầu. Điều thực sự thường là cả hai đều chạy đồng thời để cái thứ hai có thể hoạt động với dữ liệu được phân tích cú pháp bởi cái đầu tiên khi đang di chuyển. Đó là những gì xảy ra ở đây, cả hai sẽ được gọi mà không cần đợi người đầu tiên kết thúc. Điều đó áp dụng cho tất cả các dòng lệnh ống .

Tôi nghĩ rằng logic tương tự áp dụng cho: () {: |: &};: và

:(){ : & };:

Có làm cùng công việc với

:(){ :|: & };:

Cái đầu tiên sẽ không hoạt động, bởi vì mặc dù nó tự chạy theo cách đệ quy, hàm vẫn được gọi trong nền ( : &). Việc đầu tiên :không đợi cho đến khi "đứa trẻ" :trở lại trước khi tự kết thúc, vì vậy cuối cùng, bạn có thể chỉ có một phiên bản :chạy. Nếu bạn có :(){ : };:nó sẽ hoạt động, vì người đầu tiên :sẽ đợi "đứa trẻ" :trở lại, nó sẽ đợi "đứa con" của chính nó :trở lại, v.v.

Đây là cách các lệnh khác nhau trông như thế nào về số lượng phiên bản sẽ chạy:

:(){ : & };:

1 thể hiện (cuộc gọi :và cuộc gọi ) -> 1 trường hợp (cuộc gọi :và cuộc gọi ) -> 1 trường hợp (cuộc gọi :và cuộc gọi ) -> 1 trường hợp -> ...

:(){ :|: &};:

1 trường hợp (gọi 2 :'s và thoát) -> 2 trường hợp (mỗi trường hợp gọi 2 :và thoát) -> 4 trường hợp (mỗi trường hợp gọi 2 :và thoát) -> 8 trường hợp -> ...

:(){ : };:

1 trường hợp (gọi :và đợi nó trả về) -> 2 trường hợp (con gọi cuộc gọi khác :và đợi nó trả về) -> 3 trường hợp (con gọi cuộc gọi khác :và đợi nó trả về) -> 4 trường hợp -> ...

:(){ :|: };:

1 trường hợp (gọi 2 :và chờ họ quay lại) -> 3 trường hợp (trẻ gọi 2 :lần và chờ chúng quay lại) -> 7 trường hợp (trẻ gọi 2 :lần và chờ chúng quay lại) -> 15 trường hợp -> ...

Như bạn có thể thấy, việc gọi hàm trong nền (sử dụng &) thực sự làm chậm quả bom ngã ba, vì callee sẽ thoát ra trước khi các hàm được gọi trở lại.


Câu hỏi. :(){ : & && : &}; :Cũng sẽ làm việc như một quả bom ngã ba? Bạn cũng sẽ tăng theo cấp số nhân, và trên thực tế, bạn có thể đặt nhiều người : &vào đó để tăng nhanh hơn nữa.
JFA

@JFA `─> $: () {: & &&: &}; : `đưa ra lỗi cú pháp bash: syntax error near unexpected token &&' . Bạn có thể làm điều này : :(){ $(: &) && $(: &)}; :, Nhưng một lần nữa, không giống như đường ống, nó sẽ không chạy song song. Mà sẽ tương đương với :(){: & };:. Muốn xác minh? hãy thử những thứ này time $( $(sleep 1 & ) && $(sleep 1 &) )và cái nàytime $(sleep 1 | sleep 1)
Severus Tux

Chính xác, :(){ $(: &) && $(: &)};là một hàm đang phát hành một phép toán AND logic trong các giá trị trả về của thể hiện thứ nhất và thứ hai. Vấn đề là, vì logic AND chỉ đúng nếu cả hai giá trị đều đúng, vì hiệu quả chỉ có phiên bản đầu tiên sẽ được chạy. Nếu giá trị trả về của nó là 1 thì phiên bản thứ hai sẽ chạy. Nếu bạn muốn làm cho quả bom ngã ba nhanh hơn nữa, tôi nghĩ rằng bạn có thể đưa nhiều trường hợp hơn vào chuỗi, như:(){ :|:|: &}; :
IanC

Cũng như một ghi chú bên lề, nhiều tập lệnh sử dụng hành vi này của AND trong tình huống sau: Giả sử bạn muốn chạy prog2 nếu prog1 trả về true (trong bash là 0). Thay vì thực hiện một câu lệnh if ( if [ prog1 ]; then; prog2; fi), bạn chỉ có thể viết ( prog1 && prog2) và prog2 sẽ chỉ chạy nếu giá trị trả về của prog1 là đúng.
IanC

Ok, đây là tất cả những điểm tuyệt vời. Tôi sử dụng &&để gọi apt-get update && apt-get upgrade&ở cuối dòng để chạy trong nền, nhưng đó là điểm tuyệt vời mà họ sẽ không làm việc cùng nhau. Dấu chấm phẩy cũng không hoạt động với dấu và.
JFA
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.