I have tried multiple different ways to retrieve the exit status of a background process:
Con: pid is not a child of this shell
Con: exit status is always 0 here
Looked around for various answers on stackoverflow. I am still not able to get it working. Can you please help and let me know where am I going wrong?
PIDS=()
STATUS=()
OVERALL_EXIT=0
# run processes and store pids in array
for target in ${target_list} ; do
./<script_to_execute> ${target} &
PIDS+=$!
done
# wait for all processes to finish and then capture return status of each
for pid in ${PIDS[@]}; do
echo "${pid}"
wait ${pid}
#tail —pid=${pid} -f /dev/null
#ps ax | grep ${pid} | grep -v grep
STATUS+=($?)
done
# looping through the status arr to check exit code for each
i=0
for st in ${STATUS[@]}; do
if [[ ${st} -ne 0 ]]; then
echo "$i failed"
OVERALL_EXIT=1
else
echo "$i finished"
fi
((i+=1))
done
exit ${overall_exit}
PIDS+=$!
...doesn't do what you think it does. Consider:
PIDS=( )
PIDS+=11
PIDS+=22
PIDS+=33
declare -p PIDS
...if what you expect this to output is:
declare -a PIDS='([0]="11" [1]="22" [2]="33")
...you'd be mistaken, because what it actually emits is:
declare -a PIDS='([0]="112233")'
...because +=
only appends a new array element when the thing on the right-hand side is an array.
Thus, you get a not a child of this shell
error because the result of concatenating all your PIDs together into a single string isn't a PID that actually exists.
To fix it, use parens: PIDS+=( "$!" )
To provide an end-to-end example:
#!/usr/bin/env bash
# run four different processes; two exit status 0, one exits status 1, on exits status 2
# ...exits happen at delays ranging between 2-5 seconds.
delays=( 5 3 2 4 )
exits=( 0 0 1 2 )
for idx in "${!delays[@]}"; do
(sleep "${delays[$idx]}"; exit "${exits[$idx]}") &
pids+=( "$!" )
done
exit_status=0
for pid in "${pids[@]}"; do
wait "$pid"; (( exit_status |= $? ))
done
echo "Combined exit status is $exit_status"
exit "$exit_status"
...properly exits after 5 seconds with:
Combined exit status is 3