Последний бит кода, ;:
это функция :(){ ... }
. Это где вилка происходит.
Точка с запятой завершает первую команду, а мы запускаем другую, то есть вызываем функцию :
. Определение этой функции включает в себя вызов самой себя ( :
), и результат этого вызова передается в фоновую версию :
. Это поддерживает процесс на неопределенный срок.
Каждый раз , когда вы вызываете функцию :()
вы вызываете функцию 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
оболочки, из которой была выполнена команда.