我知道普通的叉子炸弹是如何工作的,但是我真的不明白为什么在普通bash叉子炸弹的末尾需要&,以及为什么这些脚本的行为有所不同:
:(){ (:) | (:) }; :
和
:(){ : | :& }; :
前者会导致CPU使用率激增,然后将我带回到登录屏幕。后者反而只会导致我的系统死机,从而迫使我进行硬重启。这是为什么?两者都不断创建新的流程,那么为什么系统的行为有所不同?
这两个脚本的行为也与
:(){ : | : }; :
即使我希望它们是相同的,这也完全不会引起任何问题。bash手册页指出,管道中的命令已在子shell中执行,因此我被认为::应该已经足够了。我相信,应该在新的子Shell中运行管道,但是为什么会有如此大的变化?
编辑:使用htop并限制进程数量,我能够看到第一个变量创建了一个实际的进程树,第二个变量创建了相同级别的所有进程,而最后一个变量似乎未创建任何进程完全没有。这使我更加困惑,但是也许可以有所帮助?
警告请勿尝试在生产机器上运行此程序。只是不要。警告:要尝试使用任何“炸弹”,请确保ulimit -u
已在使用中。阅读下面的[a]。
让我们定义一个函数来获取PID和日期(时间):
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
bomb
新用户的一个简单的非发行函数(保护自己:请阅读[a]):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
当调用该函数执行时,其工作方式如下:
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
date
执行该命令,然后打印“是”,睡眠1秒钟,然后关闭命令date
,最后,该函数退出并打印新的命令提示符。没有什么花哨。
当我们这样调用函数时:
bize:~$ bomb | bomb
START 0003365 23:11:34
yes
START 0003366 23:11:34
yes
END 0003365 23:11:35
END 0003366 23:11:35
bize:~$
两个命令有时会启动,两个命令会在1秒后结束,然后提示会返回。
这就是pipe|
并行启动两个进程的原因。
如果我们更改通话,则添加结尾&
:
bize:~$ bomb | bomb &
[1] 3380
bize:~$
START 0003379 23:14:14
yes
START 0003380 23:14:14
yes
END 0003379 23:14:15
END 0003380 23:14:15
提示将立即返回(所有操作都发送到后台),并且两个命令将像以前一样执行。请注意在[1]
该过程的PID之前打印的“作业编号”的值3380
。稍后,将打印相同的数字以指示管道已结束:
[1]+ Done bomb | bomb
那是效果&
。
这就是&
:加快进程启动速度的原因。
我们可以创建一个简单b
地执行两个命令的函数。输入三行:
bize:~$ b(){
> bomb | bomb
> }
并执行为:
bize:~$ b
START 0003563 23:21:10
yes
START 0003564 23:21:10
yes
END 0003564 23:21:11
END 0003563 23:21:11
请注意,我们;
在的定义中使用了no b
(换行符用于分隔元素)。但是,对于一行上的定义,通常使用;
,如下所示:
bize:~$ b(){ bomb | bomb ; }
大多数空格也不是强制性的,我们可以编写等效的空格(但不太清楚):
bize:~$ b(){ bomb|bomb;}
我们还可以使用a&
分隔}
(并将两个进程发送到后台)。
如果我们使函数咬尾(通过调用自身),则会得到“叉子炸弹”:
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
为了使其更快地调用更多功能,请将管道发送到后台。
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
如果我们将第一个调用追加到必填项之后,;
然后将名称更改为:
:
bize:~$ :(){ :|:&};:
或者,以有趣的方式写上另一个名字(一个雪人):
☃(){ ☃|☃&};☃
ulimit(在运行此命令之前应已设置)将使提示在出现很多错误后迅速返回(在错误列表停止时按Enter以获取提示)。
之所以称为“叉子炸弹”,是因为Shell启动子Shell的方式是分叉运行中的Shell,然后使用要运行的命令调用exec()到fork的进程。
管道将“分叉”两个新过程。达到无穷大会炸弹。
或最初被称为兔子的原因是它繁殖得如此之快。
:(){ (:) | (:) }; time :
终止
实数0m45.627s
:(){ : | :; }; time :
终止
实0m15.283s
:(){ : | :& }; time :
真正的0m00.002 s
仍在运行
:(){ (:) | (:) }; :
第二次关闭)
分隔的}
是的更复杂版本:(){ :|:;};:
。管道中的每个命令无论如何都在子外壳内部被调用。这是什么效果的()
。
:(){ : | :& }; :
是更快的版本,没有空格::(){(:)|:&};:
(13个字符)。
:(){ : | : }; :
###在zsh中有效,但在bash中无效。
出现语法错误(以bash表示),在结束之前需要一个元字符}
,
如下所示:
:(){ : | :; }; :
[a]创建一个新的干净用户(我称我为bize
)。在控制台中登录到该新用户sudo -i -u bize
,或者:
$ su - bize
Password:
bize:~$
检查然后更改max user processes
限制:
bize:~$ ulimit -a ### List all limits (I show only `-u`)
max user processes (-u) 63931
bize:~$ ulimit -u 10 ### Low
bize:~$ ulimit -a
max user processes (-u) 1000
仅使用10个作品,就只有一个单独的新用户:bize
。它使调用killall -u bize
和摆脱系统大多数(不是全部)炸弹变得更加容易。请不要问哪个仍然有效,我不会告诉您。但是仍然:相当低但是出于安全考虑,请适应您的系统。
这将确保“叉子炸弹”不会使您的系统崩溃。
进一步阅读:
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句