[Bash] 今さらFork爆弾を解析してみる

# はじめに

**※言わずもがな、お約束の自己責任でお願いします**

かの有名なFork爆弾。Bashなら以下です。
`:(){ :|: & };:`

この原理が今一つピンとこなかったので、今さらながら **動作確認がてら（！）**解析してみました。

順番通り（悪く言えばダラダラと）記載していますので、単に読み物（ポエム）としてお読みいただければありがたいです。

# 本編

## 読みやすく改変して投下

`:`の代わりに、関数名として`bomb`を使います。
`bomb() { bomb | bomb & }; bomb`

投下で**見事に炸裂、再起動が必要**となりました。まずは成功？です！

## フォアグラウンドで実行してみる

いちいち再起動するのは面倒なので、フォアグラウンドにしてみましょう。

`bomb() { bomb | bomb ; }; bomb`

こちらも同様に炸裂していますが、Ctrl+C、もしくはターミナルを閉じると何とか復帰できるようです。
解析のため、このフォアグラウンド実行は継続します。

## スリープしてみる

同じく解析に手間取りそうなので、10秒くらい待ってみます。

`bomb() {  sleep 10 ; bomb | bomb ; }; bomb`

別のターミナルで確認すると、**ゆっくり破滅に向かっていく**ことが確認できます。
（以下の`-bash`と`sleep 10`が時間とともにわらわら増えていく）

```console
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user     25428 25363  0 15:54 ?        00:00:00 sshd: user@pts/2
user     25429 25428  0 15:54 pts/2    00:00:00 -bash
user     26605 25429  0 15:56 pts/2    00:00:00 -bash
user     26606 25429  0 15:56 pts/2    00:00:00 -bash
user     26607 26606  0 15:56 pts/2    00:00:00 sleep 10
user     26608 26605  0 15:56 pts/2    00:00:00 sleep 10
user     26612 25777  0 15:56 pts/3    00:00:00 grep --color=auto pts/2
```

## ログを仕込む

`foo`というファイルにログを出すようにしてみます。
まだワンライナーで読めますね。

`` bomb() {  sleep 10 ; echo `date +%H:%M:%S.%3N`: Throw 2 bombs... >> foo ; bomb | bomb ; }; bomb ``

別ターミナルでのログの確認結果：

```console
user@user-VirtualBox:~$ tail -f foo
16:15:14.374: Throw 2 bombs...
16:15:24.378: Throw 2 bombs...
16:15:24.379: Throw 2 bombs...
16:15:34.384: Throw 2 bombs...
16:15:34.385: Throw 2 bombs...
16:15:34.388: Throw 2 bombs...
16:15:34.389: Throw 2 bombs...
```

何とも素晴らしいログ（自画自賛）！

1. 16:15:14に2個投下
1. 16:15:24に2 + 2 = 4個投下
1. 16:15:34に2 + 2 + 2 + 2 = 8個投下

よって、**倍々ゲームで爆弾（プロセス）が増えている**ことが明確になりました！
10秒スリープしていなかったらと思うと恐ろしいですね！笑

## 1個にしてみる

誰しも疑問に思うであろう（ですよね？）、1個ならどうなの？です。

`` bomb() {  sleep 10 ; echo `date +%H:%M:%S.%3N`: Throw a bomb... >> foo ; bomb ; }; bomb ``

ログは当然の結果：

```console
user@user-VirtualBox:~$ tail -f foo
16:28:09.661: Throw a bomb...
16:28:19.664: Throw a bomb...
16:28:29.668: Throw a bomb...
```

プロセスの確認結果は以下（適当に間隔を空けて確認しています）：

```console
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user     25428 25363  0 15:54 ?        00:00:00 sshd: user@pts/2
user     25429 25428  0 15:54 pts/2    00:00:00 -bash
user     26743 25429  0 16:28 pts/2    00:00:00 sleep 10
user     26746 25777  0 16:28 pts/3    00:00:00 grep --color=auto pts/2
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user     25428 25363  0 15:54 ?        00:00:00 sshd: user@pts/2
user     25429 25428  0 15:54 pts/2    00:00:00 -bash
user     26748 25429  0 16:28 pts/2    00:00:00 sleep 10
user     26750 25777  0 16:28 pts/3    00:00:00 grep --color=auto pts/2
user@user-VirtualBox:~$ ps -f -u user | grep pts/2
user     25428 25363  0 15:54 ?        00:00:00 sshd: user@pts/2
user     25429 25428  0 15:54 pts/2    00:00:00 -bash
user     26754 25429  0 16:28 pts/2    00:00:00 sleep 10
user     26756 25777  0 16:28 pts/3    00:00:00 grep --color=auto pts/2
user@user-VirtualBox:~$
```

大元の`-bash`プロセスはずっと生きていて、`sleep 10`プロセスが別個に起動していることがわかります（`26743`→`26748`→`26754`）。

すなわち、新しいプロセスは起動しているが、都度前のプロセスが終わっているので、増殖しないということかと。

平たく言ってしまえば、**単にbombを繰り返す無限ループ**ですね。


## パイプからセミコロンにしてみる

では2つの爆弾の間を、`|`でなく`;`にしたらどうなるでしょうか。

`` bomb() {  sleep 10 ; echo `date +%H:%M:%S.%3N`: Throw 1st bomb... >> foo ; bomb ; echo `date +%H:%M:%S.%3N`: Throw 2nd bomb... >> foo ; bomb ; }; bomb ``

```console
user@user-VirtualBox:~$ tail -f foo
16:42:05.384: Throw 1st bomb...
16:42:15.387: Throw 1st bomb...
16:42:25.390: Throw 1st bomb...
```

`2nd bomb`まで到達していませんね。これは`1st bomb`をひたすら繰り返しているためで、実体は爆弾1個の場合と同じです。

# おわりに

## 感想（ポエム）

百聞は一見にしかず。愚直な方法ではありましたが、また一つ賢くなりました。笑

## 確認環境

- Ubuntu 18.04 LTS（をVMで）