バックグラウンド制御演算子(&)で生成されたサブシェルがpstreeの下に表示されないのはなぜですか?

バックグラウンド制御演算子(&)で生成されたサブシェルがpstreeの下に表示されないのはなぜですか?

コマンドは同じシェルで実行されるため、コマンドを実行すると現在のシェルがexit終了することがわかります。exitまた、実行時にコマンドがサブシェルで実行されることが保証されているため、元のシェルが終了しないため、サブシェルを終了してexit &元のシェルに戻ることも学びました。しかし、私が理解していないのは、あるコマンドとないコマンドがまったく同じように見える理由です。この場合、 と 。 4669は最初に発行されたbashのPIDであり、その間に他のシェルインスタンスから次の出力を取得します。&exit&pstreesleep 10sleep 10 &sleep 10sleep 10 &

# version without &
$ pstree 4669
bash(4669)───sleep(6345)

# version with &
$ pstree 4669
bash(4669)───sleep(6364)

バージョンには、&このように生成されたサブシェル(この場合はPID 5555など)を含める必要がありますか?

bash(4669)───bash(5555)───sleep(6364)

pstreePS:より読みやすくするために、次のコードは開始出力から省略されました。

systemd(1)───slim(1009)───ck-launch-sessi(1370)───openbox(1551)───/usr/bin/termin(4510)───bash(4518)───screen(4667)───screen(4668)───

ベストアンサー1

この質問に答える前に& 制御演算子実行する働くバックグラウンドでサブシェルを起動します。コマンドが括弧で囲まれているかパイプラインの一部を形成すると、サブシェルが生成されます(パイプラインの各コマンドは独自のサブシェルで実行されます)。

これコマンドリストBashマニュアルセクション(ありがとう、ジミー)状態:

コマンドが制御演算子「&」によって終了すると、シェルはサブシェルでコマンドを非同期的に実行します。これを実行命令といいます。背景。シェルは、コマンドが完了するのを待たずに状態0(true)を返します。

sleep 10 &私が理解したのは、シェルを実行したときクロスsは新しい子プロセス(自己コピー)を作成し、すぐに実装するsは、このサブプロセスを外部コマンド()のコードに置き換えますsleep。これは、コマンドを正常に(フォアグラウンドで)実行したときに発生するのと似ています。よりFork–exec Wikipedia 記事このメカニズムの簡単な概要です。

Bashがサブシェルでバックグラウンドコマンドを実行する理由はわかりませんが、たとえばシェル組み込みコマンドを実行したり、バックグラウンドexit(外部コマンドだけでなく)でも実行したい場合はecho意味があります。

これは、自分を置き換える外部コマンドを呼び出さずにバックグラウンドforkで実行される(サブシェルの作成)シェル組み込みコマンドの場合に発生します。exec次のコマンドを実行すると、echoコマンドが中括弧で囲まれ、バックグラウンドで(使用して&)実行されたときに実際にサブシェルが生成されることがわかります。

$ { echo $BASH_SUBSHELL $BASHPID; }
0 21516
$ { echo $BASH_SUBSHELL $BASHPID; } &
[1] 22064
$ 1 22064

上記の例では、現在のシェルによる拡張をecho避けるために、コマンドを中括弧で囲みましたBASH_SUBSHELL。中括弧は、サブシェルを使用せずにコマンドをグループ化するために使用されます。コマンドの2番目のバージョン(&制御演算子で終わる)は、&記号でコマンドを終了すると、組み込みechoコマンドを実行するために新しいPIDを持つサブシェルが作成されることを明確に示しています。(ここではシェルの動作を単純化した可能性があります。mikeservの説明を参照してください。)

exit &あなたの質問を読んでいない場合は、現在のシェルが終了すると予想していた場合は、実行を考えていない可能性があります。これで、これらのコマンドがサブシェルで実行されることがわかると、サブシェルの終了の説明がわかります。


「バックグラウンド制御演算子(&)で生成されたサブシェルがpstreeの下に表示されない理由」

上記のように、Bashは実行時にsleep 10 &独自にサブシェルを生成しますが、sleep外部コマンドであるため、子exec()プロセスのBashコードとデータを実行中のプログラムのコピーにすぐに置き換えるシステムコールを呼び出しますsleep。を実行するとpstree呼び出しexecが完了し、子プロセスの名前は「眠る」。


コンピュータから離れている間にサブシェルが通過するのに十分な長さのサブシェルを実行する方法を見つけようとしていますpstree。組み込みコマンドでコマンドを実行できるようですtime

$ time sleep 11 &
[2] 4502
$ pstree -p 26793
bash(26793)─┬─bash(4502)───sleep(4503)
            └─pstree(4504)

ここで、Bashシェル(26793)は、バックグラウンドでコマンドを実行するためにサブシェル(4502)を生成するために分岐されます。このサブシェルは独自の組み込みtimeコマンドを実行し、これは分岐して実行され、外部コマンドを実行してPID 4503を使用して新しいsleepプロセスを生成します。


使用名前付きパイププレハブ牛革exit生成されたサブシェルを次のように表示するのに十分長く実行する賢い方法を考えましたpstree

$ mkfifo file
$ exit <file &
[2] 6413
$ pstree -p 26793
bash(26793)─┬─bash(6413)
            └─pstree(6414)
$ echo > file
$ jobs
[2]-  Done    exit < file

名前付きパイプからのリダイレクトは、名前付きstdinパイプから入力を受け取るまでサブシェルがブロックされるようにするため、賢明です。後でリダイレクトされた出力(引数なし)は、echo名前付きパイプに改行文字を書き込みます。これはサブシェルプロセスのロックを解除し、組み込みexitコマンドを実行します。


同様にsleep、次のコマンドも同様です。

$ mkfifo named_pipe
$ sleep 11 < named_pipe &
[1] 6600
$ pstree -p 26793
bash(26793)─┬─bash(6600)
            └─pstree(6603)

ここでは、バックグラウンドでコマンドを実行するために生成されたサブシェルのPIDです6600。次に、パイプに改行文字を作成してプロセスのロックを解除します。

$ echo > named_pipe

これにより、サブシェルがコマンドをexec実行しますsleep

$ pstree -p 26793
bash(26793)─┬─pstree(6607)
            └─sleep(6600)

呼び出し後、子プロセス()がプログラムを実行しているexec()ことがわかります。6600sleep

おすすめ記事