Bashでは、バックグラウンドジョブとして一緒に作成された別のプロセスにパイプされているプロセスのPIDを取得する必要があります。以前は単に依存していましたが、プロセスを見つけるまでに2秒以上の遅延がある可能性があることがわかりpgrep
ました。pgrep
#!/bin/bash
cmd1 | cmd2 &
pid=$(pgrep cmd1) # emtpy in about 1/10
この問題について私が見つけたいくつかの一般的なアドバイスは、単純なパイプ(cmd1 >(cmd2) & pid=$!
)の代わりにプロセス置換を使用するか、jobs
組み込み関数を使用することです。プロセスの置き換えは(フルランタイム中に)フルサブシェルを実行するので、今はそれを使用することをお勧めしますがjobs
、同じ間違いを2回繰り返さないことを願っています...
両方のプロセスを作成してすぐにルックアップを実行すると、両方のプロセスを知っているとjobs
100%信頼できますか?
#!/bin/bash
cmd1 | cmd2 &
pid=$(jobs -p %cmd1) # 10/10?
これはバックグラウンドでジョブを実行するためである可能性があり、奇妙なことになるかもしれませんが、set -x
次の例では通常実行されるコマンドをランダムな順序で一覧表示します。jobs
出力現れるjobs
これまでは正確ですが、実行される可能性は完全に排除したいと思います。今後ジョブが開始されました(または少なくともjobs
2つのプロセスをリストできません)! ?
#!/bin/bash
set -x
tail -f /dev/null | cat &
jobs -l
kill %tail
例:
+ jobs -l
[1]+ 2802325 Running tail -f /dev/null
2802326 | cat &
+ tail -f /dev/null
+ kill %tail
同様に、プロセス交換の場合でもpid=$!
常に動作すると信じられますか?正確に、「最も最近実行されたバックグラウンド(非同期)コマンドのプロセスIDに拡張」するように設計されていますか?
ベストアンサー1
バックグラウンドジョブがフォームのパイプラインであっても、それはcmd1 | cmd2
まだ単一のバックグラウンドジョブです。いつcmd1
始まるかを知る方法はありません。
それぞれは&
バックグラウンドジョブを生成します。cmd &
返されると、シェルはバックグラウンドジョブであるlistscmd & jobs
を認識しますcmd
。実行中のプロセスIDにcmd & pid=$!
設定します。pid
cmd
パイプはcmd1 | cmd2
2つの異なるサブプロセスを生成します。 1つは実行しcmd1
、もう1つは実行しますcmd2
。どちらのプロセスも、バックグラウンドジョブを実行する子プロセスの子プロセスです。プロセスツリーは次のとおりですbash -c '{ sleep 123 | sleep 456; } & jobs -p; sleep 789'
。
PID PPID CMD
268 265 | \_ bash -c { sleep 123 | sleep 456; } & sleep 789
269 268 | \_ bash -c { sleep 123 | sleep 456; } & sleep 789
270 269 | | \_ sleep 123
271 269 | | \_ sleep 456
272 268 | \_ sleep 789
268は元のbashプロセスです。 269は印刷用のバックグラウンドジョブですjobs -p
。 270と271はパイプの左右にあり、両方のサブプロセスはバックグラウンドジョブ(269)のメインプロセスです。
私がテストしたbashバージョン(Linuxでは5.0.17)は中cmd1 | cmd2 &
括弧なしで最適化されました。この場合、パイプラインの左側はバックグラウンドジョブと同じプロセスで実行されます。
PID PPID CMD
392 389 | \_ bash -c sleep 123 | sleep 456 & jobs -p; sleep 789
393 392 | \_ sleep 123
394 392 | \_ sleep 456
395 392 | \_ sleep 789
bashバージョン間、さらにはプラットフォーム、ディストリビューション、libcバージョンなどの間でも、この動作が安定していると信じることはできません。
jobs -p %cmd1
コードがで始まる採用情報を見つけますcmd1
。見つけたのはcmd1 | cmd2
。jobs -p %?cmd2
bashの組み込み機能を使用してcmd1
実行中のプロセスIDにアクセスする方法はありません。cmd2
cmd1
開始されたことを確認する必要がある場合は、プロセス置換を使用してください。
cmd1 >(cmd2)
cmd2
いつ開始して終了するのかわかりません。
cmd1
いつ開始して終了するかを知る必要がある場合は、cmd2
同時に動作させ、名前付きパイプを介して通信する必要があります。
tmp=$(mktemp -d) # Remove this in cleanup code
mkfifo "$tmp/pipe"
cmd1 >"$tmp/pipe" & pid1=$!
cmd2 <"$tmp/pipe" & pid2=$!
…
このjobs
コマンドはスクリプトではあまり役に立ちません。$!
バックグラウンドジョブのPIDを記憶するために使用されます。
1または少なくともそうする必要があります。私のバージョンでは作業仕様が不明だと文句を言いますが、作業が一つしかないとされているのでバグであること間違いありません。