パイプラインのプロセスが無効な終了コードを返すのを待っています

パイプラインのプロセスが無効な終了コードを返すのを待っています

ここに何かが抜けたようです。

#!/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終了して124で終了すると、忠実に返されます。sleepwait

しかし、初期コマンドにパイプを追加すると、次のようになります。

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

関連情報