Останній біт коду ;:
- це функція :(){ ... }
. Ось тут і виникає вилка.
Точка з комою закінчується першою командою, і ми починаємо іншу, тобто викликаємо функцію :
. Визначення цієї функції включає виклик до себе ( :
), а вихід цього виклику передається у фонову версію :
. Це підсилює процес нескінченно.
Кожен раз , коли ви викликаєте функцію :()
ви викликаєте функцію C fork()
. Врешті-решт це вичерпає всі ідентифікатори процесу (PID) в системі.
Приклад
Ви можете поміняти місцями на |:&
щось інше, щоб мати уявлення про те, що відбувається.
Встановіть вахту
В одному вікні терміналу зробіть це:
$ watch "ps -eaf|grep \"[s]leep 61\""
Налаштуйте вилкову бомбу "затриманий запобіжник"
В іншому вікні ми запустимо трохи змінену версію вилкової бомби. Ця версія спробує придушити себе, щоб ми могли вивчити, що вона робить. Наша версія буде спати 61 секунду до виклику функції :()
.
Також ми будемо фоновувати початковий дзвінок, після його виклику. Ctrl+ z, потім введіть bg
.
$ :(){ sleep 61; : | : & };:
# control + z
[1]+ Stopped sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &
Тепер, якщо ми запустимо jobs
команду в початковому вікні, ми побачимо це:
$ jobs
[1]- Running sleep 61 &
[2]+ Running : | : &
Через пару хвилин:
$ jobs
[1]- Done sleep 61
[2]+ Done : | :
Зареєструйтесь у спостерігача
Тим часом в іншому вікні, де ми працюємо 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
Ієрархія процесу
І ps -auxf
показує ієрархію цього процесу:
$ 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
...
...
Час прибирання
А killall bash
зупинить справи, перш ніж вони вийдуть з-під руки. Прибирання таким чином може бути дещо важким, більш добрий спосіб, який потенційно не зможе зірвати кожногоbash
шкаралупу, - це зробити наступне:
Визначте, на якому псевдотерміналі збирається вилка бомба
$ tty
/dev/pts/4
Убити псевдотермінал
$ pkill -t pts/4
Отже, що відбувається?
Добре кожен виклик bash
і sleep
є викликом функції C fork()
з bash
оболонки, з якої була запущена команда.