トラップ機能でCHLDサブシェルを区別する

トラップ機能でCHLDサブシェルを区別する

このbashスクリプトがあります。

#!/usr/bin/env bash

set -m          # allow for job control
EXIT_CODE=0     # exit code of overall script

function foo() {
   echo "CHLD pid is $!"   # doesn't seem to be the expected pid
   echo "CHLD exit code is $?"  #exit code seems to pertain to some other process
   if [[ $? > 0 ]]; then
      echo "at least one test failed"
      EXIT_CODE=1
   fi
}

trap 'foo' CHLD

DIRN=$(dirname "$0")

commands=(
    "echo 'foo'; exit 1;"
    "echo 'bar'; exit 0;"
    "echo 'baz'; exit 2;"
)

clen=`expr "${#commands[@]}" - 1` # get length of commands - 1

for i in `seq 0 "$clen"`; do
    (echo "${commands[$i]}" | bash) &   # run the command via bash in subshell
    echo "$i ith command has been issued as a background job"
done

# wait for all to finish
wait

echo "EXIT_CODE => $EXIT_CODE"
exit "$EXIT_CODE"

複数のサブシェルが終了し、終了時にfoo関数がトリガーされます。私はfoo関数が3つのCHLDイベントのみをキャプチャすると予想しましたが、実際には少なくとも6つありました。

CHLD関数で発生するイベントをどのように区別しますかfoo

たとえば、上記のスクリプトの出力は次のようになります。

CHLD exit code is 0
CHLD exit code is 0
CHLD exit code is 0
0 ith command has been issued as a background job
1 ith command has been issued as a background job
2 ith command has been issued as a background job
bar
baz
foo
CHLD exit code is 0
CHLD exit code is 0
CHLD exit code is 0
EXIT_CODE => 0

ご覧のとおり、6つのCHLDイベントがありますが、実際には3つだけ興味があります。また、0,0,0ではなく1,0,2を終了コードと見なす必要があります。

だから、2つの質問があります。

  1. foo関数内で終了するサブシェルを識別する方法はありますか?
  2. 1または2でなければならない終了コードが0で表示されるのはなぜですか?

答え1

関数の合計値がなぜ$?問題なのかはわかりませんが、次の修正は、関​​数内で合計値を使用して問題を解決するようです。$!fooCHLDjobs -pfoo

#!/usr/bin/env bash

set -m          # allow for job control
EXIT_CODE=0     # exit code of overall script

function foo() {
    for job in `jobs -p`; do
        echo "PID => ${job}"
        if ! wait ${job} ; then
            echo "At least one test failed with exit code => $?" ;
            EXIT_CODE=1;
        fi
    done
}

trap 'foo' CHLD

DIRN=$(dirname "$0")

commands=(
    "{ echo 'foo' && exit 4; }"
    "{ echo 'bar' && exit 3; }"
    "{ echo 'baz' && exit 5; }"
)

clen=`expr "${#commands[@]}" - 1` # get length of commands - 1

for i in `seq 0 "$clen"`; do
    (echo "${commands[$i]}" | bash) &   # run the command via bash in subshell
    echo "$i ith command has been issued as a background job"
done

wait       # wait for all to finish

echo "EXIT_CODE => $EXIT_CODE"
exit "$EXIT_CODE"

関連情報