
コマンドは同じシェルで実行されるため、コマンドを実行すると現在のシェルがexit
終了することがわかります。exit
また、実行時にコマンドがサブシェルで実行されることが保証されているため、元のシェルが終了しないため、サブシェルを終了してexit &
元のシェルに戻ることも学びました。しかし、私が理解していないのは、あるコマンドとないコマンドがまったく同じように見える理由です。この場合、 と 。 4669は最初に発行されたbashのPIDであり、その間に他のシェルインスタンスから次の出力を取得します。&
exit
&
pstree
sleep 10
sleep 10 &
sleep 10
sleep 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)
pstree
PS:より読みやすくするために、次のコードは開始出力から省略されました。
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()
ことがわかります。6600
sleep