web-dev-qa-db-ja.com

PIDバックグラウンドプロセス

パイプとコマンドを理解しているので、bashは各コマンドを受け取り、各コマンドのプロセスを生成し、前のコマンドのstdoutを次のコマンドのstdinに接続します。

たとえば、「ls -lsa | grep feb」では、bashは2つのプロセスを作成し、「ls-lsa」の出力を「grepfeb」の入力に接続します。

Bashで「sleep30&」のようなバックグラウンドコマンドを実行すると、コマンドを実行しているバックグラウンドプロセスのpidを取得します。驚いたことに、「ls -lsa | grep feb&」と書いたとき、bashは1つのPIDしか返しませんでした。

これはどのように解釈されるべきですか?プロセスは「ls-lsa」と「grepfeb」の両方を実行しますか?いくつかのプロセスが作成されますが、そのうちの1つのpidしか取得できませんか?

2
Raul

2つのプロセスを生成します。 &2番目のプロセスのPIDを表示します。以下の例。

$ echo $$
13358
$ sleep 100 | sleep 200 &
[1] 13405
$ ps -ef|grep 13358
ec2-user 13358 13357  0 19:02 pts/0    00:00:00 -bash
ec2-user 13404 13358  0 19:04 pts/0    00:00:00 sleep 100
ec2-user 13405 13358  0 19:04 pts/0    00:00:00 sleep 200
ec2-user 13406 13358  0 19:04 pts/0    00:00:00 ps -ef
ec2-user 13407 13358  0 19:04 pts/0    00:00:00 grep --color=auto 13358
$
1
steve

バックグラウンドでジョブを実行すると、bashはそのサブプロセスのプロセスID(そのジョブでコマンドを実行するプロセスID)を出力します。そのジョブがたまたまより多くのサブプロセスを作成する場合、それは親シェルのビジネスではありません。

バックグラウンドジョブがパイプラインである場合(つまり、コマンドがsomething1 | something2 &の形式であり、たとえば{ something1 | something2; } &ではない場合)、POSIXによって強く提案され、bashを含むほとんどのシェルによって実行される最適化があります。パイプラインの要素は、元のシェルのサブプロセスとして直接実行されます。 POSIXで義務付けられているのは、この場合、 変数$! がパイプラインの最後のコマンドに設定されることです。ほとんどのシェルでは、その最後のコマンドは元のプロセスのサブプロセスであり、パイプライン内の他のコマンドも同様です。

ls -lsa | grep febを実行すると、3つのプロセスが関係します。パイプの左側を実行するプロセス(パイプのセットアップを完了してからlsを実行するサブシェル)、実行するプロセスです。パイプの右側(パイプのセットアップを終了したサブシェルはgrepを実行します)、およびパイプの終了を待機する元のプロセス。

プロセスをトレースすることで、何が起こるかを見ることができます。

$ strace -f -e clone,wait4,pipe,execve,setpgid bash --norc
execve("/usr/local/bin/bash", ["bash", "--norc"], [/* 82 vars */]) = 0
setpgid(0, 24084)                       = 0
bash-4.3$ sleep 10 | sleep 20 &
…

2番目のsleep$!として報告および保存される方法に注意してください。ただし、プロセスグループIDは最初のsleepです。ダッシュには同じ奇妙さがありますが、kshとmkshにはありません。