ここで何かが抜けているに違いありません:
#!/bin/bash
timeout 5 sleep 10 &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"
スクリプトを呼び出しwait-pid
て実行します:
$ ./wait-pid
exit code: 124
これは私が期待したとおりで、プロセスをtimeout
強制終了しsleep
、124 で終了し、wait
忠実に戻ります。
しかし、最初のコマンドにパイプラインを追加すると、次のようになります。
timeout 5 sleep 10 | cat &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"
今私は得ます:
$ ./wait-pid
exit code: 0
wait
待機中のプロセスの終了コードをまだ返すべきではありません: timeout
。したがって、終了コードは依然として 124 であるべきではありません。
これはbash 4.4.20(1)リリースです。
答え1
私は、bash メーリング リストで非常に知識豊富な Greg Wooledge から回答を受け取りました。重要な要素は次のとおりです。
wait コマンドは、シェルの直接の子プロセス、つまり「非同期コマンド」でのみ機能します。非同期コマンドがパイプラインである場合は、元の sh 機能セットに戻ります。非同期コマンドの終了ステータスは、パイプラインの最後のコマンドの終了ステータスであり、他のコマンドの終了ステータスは単に破棄されます。
そのため、timeout
パイプライン内にある場合、終了コードを取得できません。
必要な動作を実現するには、一時ファイルを使用して、非同期コード内から終了コードをキャプチャします。次のようになります。
{
timeout 5 sleep 10 | cat
echo "${PIPESTATUS[@]}" > "$tempfile"
} &
wait