bashが単純なコマンドのサブシェルを生成しないのはなぜですか?

bashが単純なコマンドのサブシェルを生成しないのはなぜですか?

次の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

sleeptop出力リダイレクトを使用して同じ動作を再現できます。

$ 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 単純なコマンドの直接実行

このため、bash2番目の例では複数のステートメントがあることが認識されているため、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

おすすめ記事