コマンドを実行した後
{ sleep 5; } &
ps
の出力は(出力1)です
PID TTY TIME CMD
972 ttys000 0:00.27 -bash
2556 ttys000 0:00.00 -bash
2557 ttys000 0:00.00 sleep 5
の間
( sleep 5 ) &
out of ps
is(output 2)
PID TTY TIME CMD
972 ttys000 0:00.28 -bash
2566 ttys000 0:00.00 sleep 5
()
はサブシェル環境を引き起こし、現在のシェルで実行される{ sleep 5; } &
の「出力2」を期待しながら子プロセスをフォークするため、この場合は「出力1」を期待します。これはばかげた質問に見えるかもしれませんが、私はこの振る舞いを本当に理解していません。
ここで何が欠けていますか?
Bashは、サブシェルの最後のコマンドまたは唯一のコマンドを実行します with exec
最適化として安全に実行できることがわかった場合。 pstree
でこれを明確に検証できます:
$ pstree $$
bash---pstree
$ ( pstree $$ )
bash---pstree
$ ( pstree $$ ; echo)
bash---bash---pstree
$
そのため、( sleep 5 )
はsleep
コマンドとしてのみ表示され、中間シェルは表示されません。上記の最後の例では、echo
はpstree
の完了後にシェルに何かを強制するため、実際に使用するシェルがあります。中間のケースでは、生成されたシェルはすぐにexec
s pstree
になるため、最初のケースと同じように見えます(これは標準的な fork-exec )。多くのシェルがこれを行います。
一方、バックグラウンドで実行するものは、新しいプロセスを生成する必要があります:基本的に、それはそれです「背景」です。中かっこdo内のコマンドは通常、現在のシェルで実行されますが、バックグラウンドで実行する場合は実行できません。親シェルがバックグラウンドコマンドの実行中に何をしていても続けることができるように、{ ... }
全体を実行するために新しいシェルを作成する必要があります。
$ { pstree $$ ; }
bash---pstree
$ { pstree $$ ; } &
bash---bash---pstree
この場合、後続のコマンドがあるかどうかに関係なく、違いはありません。 Bashは&
のこの動作を文書化します:
コマンドが制御演算子 ‘
&
’によって終了された場合、シェルはコマンドをサブシェルで非同期的に実行します。これは、コマンドをバックグラウンドで実行することとして知られています。シェルはコマンドが完了するまで待機せず、戻りステータスは0(真)です。
read
=のような組み込みコマンドをバックグラウンド化することで、これが行われていることも確認できます。
$ read &
$ pstree $$
[1] 32394
[1]+ Stopped read
$ pstree $$
bash-+-bash
`-pstree
私のシェルにはtwoの2つの子があります:bash
実行中のread
と、その出力を出力するpstree
コマンド。
シェルがさらに最適化を行い、それをバックグラウンドの{ ... }
に適用できることは事実ですが、括弧で囲まれたサブシェルの場合と同じですが、そうではありません。他のいくつかのシェルでも可能ですが、簡単なテストでは見つかりませんでした。これはかなりまれなケースであり、正式には異なり、いくつかの奇妙なコーナーケースがあります。