web-dev-qa-db-ja.com

なぜ$!バックグラウンドで実行されているサブシェルに間違ったプロセスIDを返しますか?

$(sleep 5) &
echo $!
sleep 1
echo "done"

上記の出力:

$ ./test.sh
7483
done

ただし、ps auxsleepを検索すると、次のようになります。

 ps aux | rg sleep
chris     7484  0.0  0.0 132788  1432 pts/6    S+   12:10   0:00 sleep 1
chris     7485  0.0  0.0 132788  1432 pts/6    S+   12:10   0:00 sleep 5
chris     7519  0.0  0.0  10376  5744 pts/7    S+   12:10   0:00 rg --no-ignore-vcs sleep

スリープ5プロセスは7485であり、スクリプトからの出力として7483ではありません。この動作の原因は何ですか?

4
$(sleep 5)

sleepを実行するシェルを実行します。 $!によって提供されるPIDはシェルのものです。

ここでの置換は必要ありません。

 sleep 5 &

sleepのpidが表示されます。

あなたの例のsleepは他のものを置き換えると思いますが、いずれにしても、バックグラウンド置換はおそらく不要です。サブシェルのみを使用して、

(sleep 5) &

多くのシェルは、サブシェルで最後のコマンドを実行すると子コマンドに置き換えられ、sleepのサブシェルのpidを効果的に再利用するため、通常はsleepのpidを取得します。だが

(sleep 5; sleep 5) &

sleepではなく、シェルのPIDを取得します。

8
Stephen Kitt