Get Exit Code of a Background Process

Get exit status of background processes in bash

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

Bash: How to get exit code of a command while using a spinner?

wait will tell you what exit status a child PID exited with (by setting that program's exit status as its own), when given that PID as an argument.

sleep 2 & sleep_pid=$!
spinner "$sleep_pid"
wait "$sleep_pid"; exitCode=$?

echo "exitcode: $exitCode"

Note that combining multiple commands onto a line when collecting $! or $? in the second half is a practice I strongly recommend -- it prevents the value you're trying to collect from being changed by mistake (as by someone adding a new log line to your code later and not realizing it has side effects).

Get exit status of child process on background

After the child process has been spawned, the parent will need to call waitpid periodically with the WNOHANG flag. Using this flag will cause the function to return immediately, after which you need to check the status to see if the process actually exited or not.

For example:

int child_done;
do {
// do something useful

child_done=0;
if (waitpid(pid,&status,WNOHANG) > 0) {
if (WIFEXITED(status)) {
printf("child exited with status %d\n", WEXITSTATUS(status));
child_done = 1;
}
if (WIFSIGNALED(status)) {
printf("child terminated by signal %d\n", WTERMSIG(status));
child_done = 1;
}
}
} while (!child_done);


Related Topics



Leave a reply



Submit