次の2つのbashコマンドを考えてみましょう。 1つはサブシェルを作成し、もう1つは作成しません。
種子皮なし
$ bash -c "sleep 10000 "
pstree出力:
bash,100648
└─sleep,103509 10000
テープシェル
$ bash -c "sleep 10000; sleep 99999 "
bash,100648
└─bash,103577 -c sleep 10000; sleep 99999
└─sleep,103578 10000
一種の最適化ですか? Bashはコマンドを見て、単純なコマンドについてはプロセス生成をスキップします。この単純なコマンドは、親端末のbashによって生成されたようです。
私が使用しているBashのバージョンは
$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
しかし、bash 3.Xでも同じ状況が観察されると思います。
より多くの例。組み込みコマンドを使用すると、サブシェルが生成されます。組み込み機能は親 bash では実行されません。
$ bash -c "read"
bash,100648
└─bash,104336 -c read
sleep
top
出力リダイレクトを使用して同じ動作を再現できます。
$ bash -c "top -b "
bash,100648
└─top,104392 -b
そして
$ bash -c "top -b > /dev/null "
bash,100648
└─bash,104420 -c top -b > /dev/null
└─top,104421 -b
答え1
最初の例では、PID 100648を持つシェルは対話型シェルであり、sleep
実際には交換bash -c ''
プロセスです。execve()
システムコール呼び出された元のプロセスのPIDを保持する新しいプログラムを作成するため、元のプロセスはbash -c ''
表示されません。シェルプロセスを単純なコマンドで置き換える簡単な理由は、次の説明に従ってリソースを節約するためです。スティーブンの答え到着単純なbashコマンドに明白な複製や分岐がないのはなぜですか?。
これは、端末の簡単なテストでも確認できます。
$ echo $$
10250
$ bash -c 'sleep 60'
他の記事では:
$ pstree -p 10250
bash(10250)───sleep(21031)
なぜこのようなことが起こるのかはパイプもなく、簡単な命令しかないからです。bash
単純なコマンドの直接実行。
このため、bash
2番目の例では複数のステートメントがあることが認識されているため、sleep
最初"sleep 10000; sleep 99999 "
の場合はexecve()
新しいプロセスが終了したときに親プロセスを置き換えることができます。問題ありません。ただし、ここでは最初のコマンドが完了した後にシェルを終了できません。したがって、sleep 10000
出力で見ることができるのと同じフォークとexecveがあり、pstree
後で新しいフォークとexecveがあります。sleep 99999
実行できるもう1つのテストは、単純なコマンドがシェルbash -c ''
プロセスを置き換えると信じることです。
$ bash -c 'grep "^Pid:" /proc/self/status /proc/$$/status'
/proc/self/status:Pid: 23946
/proc/23946/status:Pid: 23946
この動作は bash にのみ適用されます。 Debianベースのディストリビューションの場合/bin/dash
(でも確認可能strace
):
$ sh -c 'grep "^Pid:" /proc/self/status /proc/$$/status'
/proc/self/status:Pid: 24188
/proc/24187/status:Pid: 24187
答え2
の出力は誤解を招く場合がpstree
あります。
bash -c "sleep 10000 "
Bashサブプロセスが実際に作成されました。ただし、プロセスは他のサブプロセスを生成しません。シェルを実行したsleep
後は何もする必要はないので、最初にexecve()
フォークせずにすぐに進むことができます。sleep
execve
速度が速すぎるので、後でのみ結果を見ることができますpstree
。
しかし、
bash -c "sleep 10000; sleep 99999 "
新しいbashケースは、各コマンドに対して1回、2回フォークされます。execve
最初に分岐するのではなく、最後のコマンドを実行することもできます。なぜできないのかわかりません。
このケースとリダイレクトのケースは、ブランチが必要な場合の検出の問題かもしれません。