web-dev-qa-db-ja.com

典型的なシェルの「フォーク爆弾」はどのように正確に2回呼び出されますか?

Askubuntuや他の多くのStack Exchangeサイトで有名な Fork Bombの質問 を調べた後、誰もが言っていることが明白であるようによくわかりません。

多くの答え( 最良の例 )はこれを言います:

「_{:|: &}_は、関数_:_を実行し、その出力を_:_関数に再度送信することを意味します」

まあ、正確には_:_の出力は何ですか?他の_:_には何が渡されますか?

そしてまた:

基本的に、すべての呼び出しを自分自身twiceで呼び出す関数を作成しており、自分自身を終了する方法がありません。

それはどのように正確に実行されますかtwice?私の意見では、最初の_:_が実行を完了するまで、2番目の_:_には何も渡されません。

たとえば、Cでは、

_foo()
{
    foo();
    foo(); // never executed 
}
_

最初のfoo()が終わらないからといって、2番目のfoo()はまったく実行されません。

同じロジックが:(){ :|: & };:にも当てはまると思います

_:(){ : & };:
_

同じ仕事をします

_:(){ :|: & };:
_

ロジックを理解してください。

15
Severus Tux

パイピングでは、最初のインスタンスが他のインスタンスが開始する前に終了する必要はありません。実際、実際に行っていることは、最初のインスタンスのstdoutを2番目のインスタンスのstdinにリダイレクトすることだけなので、同時に実行できます(フォーク爆弾が動作するように)。

さて、:の出力は正確には何ですか?他の:に何が渡されていますか?

':'は他の ':'インスタンスに何も書き込みません。それはstdoutを2番目のインスタンスのstdinにリダイレクトするだけです。 If実行中に何かを書き込みます(自分自身をフォークするだけなので何もしない)それは他のインスタンスのstdinに行きます。

stdinstdoutを重ねて考えると役立ちます:

stdinに書き込まれたものはすべて、プログラムがそれを読み取ることを決定したときに備えて積み上げられますが、-stdoutは同じように機能します。書き込み可能なパイル、そのため、他のプログラムは必要なときにそこから読み取ることができます。

このようにして、通信が行われていないパイプ(2つの空のパイル)や非同期の書き込みと読み取りのような状況を想像するのは簡単です。

それはどれほど正確に2回実行されますか?私の意見では、最初の:が実行を完了するまで、2番目の:には何も渡されません。

インスタンスの入力と出力をリダイレクトするだけなので、最初のインスタンスが2番目のインスタンスの開始前に終了する必要はありません。通常、両方を同時に実行して、2番目が最初のデータによってその場で解析されるデータを処理できるようにすることが実際に望まれます。これがここで行われることです。どちらも最初の呼び出しが完了するのを待つ必要なく呼び出されます。これは、すべてのパイプチェーンコマンド行に適用されます。

同じロジックが:(){:|:&} ;:にも当てはまると思います

:(){ : & };:

同じ仕事をします

:(){ :|: & };:

最初のものは機能しません。それ自体は再帰的に実行されていますが、関数はバックグラウンドで呼び出されているためです(: &)。最初の:は、「子」の:が戻るまで待機せずに終了するため、結局、おそらく:のインスタンスが1つだけ実行されます。最初の:は「子」:が戻るのを待ち、それが独自の「子」:が戻るのを待つため、:(){ : };:がある場合でも機能します。

実行されるインスタンスの数に関して、さまざまなコマンドは次のようになります。

:(){ : & };:

1つのインスタンス(:を呼び出して終了)-> 1つのインスタンス(:を呼び出して終了)-> 1つのインスタンス(:を呼び出して終了)-> 1つのインスタンス-> ...

:(){ :|: &};:

1つのインスタンス(2つの:を呼び出して終了する)-> 2つのインスタンス(それぞれが2つの:を呼び出して終了する)-> 4つのインスタンス(それぞれが2つの:を呼び出して終了する)-> 8つのインスタンス-> ...

:(){ : };:

1つのインスタンス(:を呼び出して戻るのを待つ)-> 2つのインスタンス(子が別の:を呼び出して戻るのを待つ)-> 3つのインスタンス(別の:を呼び出して戻るのを待つ)-> 4つのインスタンス-> ...

:(){ :|: };:

1つのインスタンス(2つの:を呼び出し、それらが戻るのを待つ)-> 3つのインスタンス(それぞれ2つの:を呼び出し、それらが戻るのを待つ)-> 7つのインスタンス(2つの:をそれぞれ呼び出し、それらが戻るのを待つ)-> 15インスタンス-> ...

ご覧のとおり、(&を使用して)バックグラウンドで関数を呼び出すと、実際にはフォーク爆弾が遅くなります。これは、呼び出された関数が戻る前に呼び出し先が終了するためです。

26
IanC