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?
  • 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. – muru Feb 13 '17 at 10:32
  • @muru IRL I am not using echo, instead I am using something that actually might want to run as background process :) – Alexander Mills Feb 13 '17 at 10:35
  • OK... I didn't say anything about echo. – muru Feb 13 '17 at 10:40
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"
  • 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. – Alexander Mills Feb 14 '17 at 2:13
  • shellcheck.net – Tomasz Feb 14 '17 at 2:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.