Đườ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 stdin và stdout 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.
:|:
, thứ hai:
không cần đợi cái đầu tiên hoàn thành.