3

I have this bash script:

#!/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"

Multiple subshells exit, and fire the foo function upon exit. I would have only expected 3 CHLD events captured by the foo function, but there are at least 6.

How can I discriminate between the CHLD events that appear in the foo function?

For example, here is the output of the above script:

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

As you can see, there are 6 CHLD events; but I really only care about 3. Furthermore, I should be seeing 1,0,2 as exit codes, not 0,0,0.

So I have two questions:

  1. Is there a way to id which subshell is exiting in the foo function?
  2. Why am I seeing 0 for the exit code, when it should be 1, or 2?
3
  • 1
    The extra CHLD events are from the various (unnecessary) subshells you used, $(dirname ...), `expr ...`,`seq ...`, and I don't think $! will contain the exit status of backgrounded processes. Commented Feb 13, 2017 at 10:32
  • @muru IRL I am not using echo, instead I am using something that actually might want to run as background process :) Commented Feb 13, 2017 at 10:35
  • OK... I didn't say anything about echo. Commented Feb 13, 2017 at 10:40

1 Answer 1

2

Not sure why the $? and $! values in the foo function don't pertain to the CHLD in question, but the following fixes seem to get around the problem, by using jobs -p inside the foo function, like so:

#!/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"
2
  • I heard from someone that jobs -p / wait <pid> does not work for subshells that have already finished, but in my experience it does. Maybe this depends on bash version. Commented Feb 14, 2017 at 2:13
  • shellcheck.net Commented Feb 14, 2017 at 2:35

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.