Sev*_*Tux 16 command-line bash fork
在浏览了Askubuntu 和许多其他 Stack Exchange 站点上著名的Fork Bomb 问题之后,我不太明白每个人在说什么,因为这很明显。
许多答案(最佳示例)是这样说的:
"
{:|: &}表示运行该函数:并将其输出:再次发送给该函数 "
那么,输出究竟是什么:?传递给对方的是:什么?
并且:
本质上,您正在创建一个函数,该函数每次调用都会调用两次,并且没有任何方法可以终止自身。
究竟是如何执行两次的?在我看来,:在第一个:完成执行之前,不会将任何内容传递给第二个,这实际上永远不会结束。
在C例如,
foo()
{
foo();
foo(); // never executed
}
Run Code Online (Sandbox Code Playgroud)
第二个foo()根本没有执行,只是因为第一个foo()永远不会结束。
我认为同样的逻辑适用于:(){ :|: & };:和
:(){ : & };:
Run Code Online (Sandbox Code Playgroud)
做同样的工作
:(){ :|: & };:
Run Code Online (Sandbox Code Playgroud)
请帮助我理解逻辑。
Ian*_*anC 26
管道不要求第一个实例在另一个实例开始之前完成。实际上,它真正要做的就是将第一个实例的stdout重定向到第二个实例的stdin,因此它们可以同时运行(因为它们必须使 fork 炸弹工作)。
那么,究竟是什么输出
:?传递给对方的是:什么?
':' 没有向另一个 ':' 实例写入任何内容,它只是将标准输出重定向到第二个实例的标准输入。如果它在执行期间写了一些东西(它永远不会,因为它除了分叉自己什么都不做)它会转到另一个实例的标准输入。
将stdin和stdout想象成一堆是有帮助的:
写入stdin 的任何内容都会在程序决定从中读取时堆积起来,而stdout 的工作方式相同:您可以写入一堆,以便其他程序可以在需要时从中读取。
这样很容易想象这样的情况,比如没有发生通信的管道(两个空堆)或非同步写入和读取。
究竟是如何执行两次的?在我看来,
:在第一个:完成执行之前,不会将任何内容传递给第二个,这实际上永远不会结束。
由于我们只是重定向实例的输入和输出,因此不需要在第二个实例开始之前完成第一个实例。实际上通常希望两者同时运行,以便第二个可以动态处理第一个正在解析的数据。这就是这里发生的事情,两者都将被调用而无需等待第一个完成。这适用于所有管道链命令行。
我认为同样的逻辑适用于 :(){ :|: & };: 和
Run Code Online (Sandbox Code Playgroud):(){ : & };:做同样的工作
Run Code Online (Sandbox Code Playgroud):(){ :|: & };:
第一个不起作用,因为即使它自己递归运行,该函数也在后台调用 ( : &)。第一个:不会等到“孩子”:返回才结束自己,所以最后你可能只有一个:运行实例。如果你有:(){ : };:它会工作,因为第一个:会等待“孩子”:返回,它会等待自己的“孩子”:返回,依此类推。
以下是不同命令在运行的实例数量方面的外观:
:(){ : & };:
1 个实例(调用:和退出)-> 1 个实例(调用:和退出)-> 1 个实例(调用:和退出)-> 1 个实例-> ...
:(){ :|: &};:
1 个实例(调用 2:并退出)-> 2 个实例(每个调用 2:并退出)-> 4 个实例(每个调用 2:并退出)-> 8 个实例-> ...
:(){ : };:
1 个实例(调用:并等待它返回)-> 2 个实例(子调用另一个实例:并等待它返回)-> 3 个实例(子调用另一个实例:并等待它返回)-> 4 个实例-> ...
:(){ :|: };:
1 个实例(调用 2:并等待他们返回)-> 3 个实例(孩子们:每个调用 2并等待他们返回)-> 7 个实例(孩子们:每个调用 2并等待他们返回) -> 15 个实例 -> ...
如您所见,在后台调用该函数(使用&)实际上会减慢 fork 炸弹的速度,因为被调用者将在被调用函数返回之前退出。