Bit cuối cùng của mã, ;:
đang chạy hàm :(){ ... }
. Đây là nơi xảy ra ngã ba.
Dấu chấm phẩy chấm dứt lệnh đầu tiên và chúng ta đang bắt đầu một lệnh khác, tức là gọi hàm :
. Định nghĩa của hàm này bao gồm một lệnh gọi đến chính nó ( :
) và đầu ra của lệnh gọi này được chuyển sang phiên bản nền :
. Đạo cụ này lên quá trình vô thời hạn.
Mỗi khi bạn đang gọi điện thoại chức năng :()
bạn đang gọi hàm C fork()
. Cuối cùng, điều này sẽ làm cạn kiệt tất cả các ID quá trình (PID) trên hệ thống.
Thí dụ
Bạn có thể trao đổi |:&
với một cái gì đó khác để bạn có thể biết được chuyện gì đang xảy ra.
Thiết lập trình theo dõi
Trong một cửa sổ đầu cuối làm điều này:
$ watch "ps -eaf|grep \"[s]leep 61\""
Cài đặt bom ngã ba "cầu chì bị trì hoãn"
Trong một cửa sổ khác, chúng tôi sẽ chạy một phiên bản sửa đổi một chút của bom ngã ba. Phiên bản này sẽ cố gắng điều tiết để chúng ta có thể nghiên cứu những gì nó đang làm. Phiên bản của chúng tôi sẽ ngủ trong 61 giây trước khi gọi chức năng :()
.
Ngoài ra, chúng tôi cũng sẽ thực hiện cuộc gọi ban đầu, sau khi nó được gọi. Ctrl+ z, sau đó gõ bg
.
$ :(){ sleep 61; : | : & };:
# control + z
[1]+ Stopped sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &
Bây giờ nếu chúng ta chạy jobs
lệnh trong cửa sổ ban đầu, chúng ta sẽ thấy điều này:
$ jobs
[1]- Running sleep 61 &
[2]+ Running : | : &
Sau một vài phút:
$ jobs
[1]- Done sleep 61
[2]+ Done : | :
Kiểm tra với người theo dõi
Trong khi đó ở cửa sổ khác nơi chúng tôi đang chạy watch
:
Every 2.0s: ps -eaf|grep "[s]leep 61" Sat Aug 31 12:48:14 2013
saml 6112 6108 0 12:47 pts/2 00:00:00 sleep 61
saml 6115 6110 0 12:47 pts/2 00:00:00 sleep 61
saml 6116 6111 0 12:47 pts/2 00:00:00 sleep 61
saml 6117 6109 0 12:47 pts/2 00:00:00 sleep 61
saml 6119 6114 0 12:47 pts/2 00:00:00 sleep 61
saml 6120 6113 0 12:47 pts/2 00:00:00 sleep 61
saml 6122 6118 0 12:47 pts/2 00:00:00 sleep 61
saml 6123 6121 0 12:47 pts/2 00:00:00 sleep 61
Quy trình phân cấp
Và một ps -auxf
hiển thị phân cấp quá trình này:
$ ps -auxf
saml 6245 0.0 0.0 115184 5316 pts/2 S 12:48 0:00 bash
saml 6247 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
....
....
saml 6250 0.0 0.0 115184 5328 pts/2 S 12:48 0:00 bash
saml 6268 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6251 0.0 0.0 115184 5320 pts/2 S 12:48 0:00 bash
saml 6272 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6252 0.0 0.0 115184 5324 pts/2 S 12:48 0:00 bash
saml 6269 0.0 0.0 100988 464 pts/2 S 12:48 0:00 \_ sleep 61
...
...
Dọn dẹp thời gian
A killall bash
sẽ dừng mọi thứ trước khi chúng ra khỏi tầm tay. Làm sạch bạn theo cách này có thể hơi nặng tay, một cách nhẹ nhàng hơn mà không có khả năng xé mọi bash
vỏ sò, sẽ là làm như sau:
Xác định thiết bị đầu cuối giả nào mà bom ngã ba sẽ chạy trong
$ tty
/dev/pts/4
Giết thiết bị đầu cuối giả
$ pkill -t pts/4
Vì vậy những gì đang xảy ra?
Vâng, mỗi lần gọi bash
và sleep
là một lệnh gọi hàm C fork()
từ trình bash
bao nơi lệnh được chạy.