この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つの質問があります。
- foo関数内で終了するサブシェルを識別する方法はありますか?
- 1または2でなければならない終了コードが0で表示されるのはなぜですか?
答え1
関数の合計値がなぜ$?
問題なのかはわかりませんが、次の修正は、関数内で合計値を使用して問題を解決するようです。$!
foo
CHLD
jobs -p
foo
#!/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"