3

In Bash, I want to call a command multiple times in parallel, while capturing all the processes exit codes.

I know how to start and wait for them, but wait will only give me the exit code of the last process exiting. I also need the exit code of the shorter lived processes.

Unfortunately I don't have bash 4.3, so wait -n is not an option, nor is gnu parallel as suggested in #3004811

#16032001 pretty much asks the same question but no solution was offered there either.

The only way I can currently think of is writing a helper script that stores the exit codes in a file, but this doesn't sound like a clean solution.

TobiM
  • 151
  • 1
  • 8
  • This answer could be useful https://stackoverflow.com/a/1048390/5291015 – Inian Sep 13 '17 at 09:27
  • in `C` you can do this. But you should notice that you have to wait for all processes to be terminated one-by-one. When a process exits, **wait** family clean up them one by one. **exit status of multiple parallel processes does not make sense** – Shakiba Moshiri Sep 13 '17 at 09:44
  • I know I can do this in C, but I have very limited ressources on that server, and generally would not like to mess with the executables there (It's a Xen server). Maybe i used incurrect wording, but i want to start, say 10 backup processes in parallel, and need to check if each of them succeeded. – TobiM Sep 13 '17 at 09:48
  • I understood what you said. I want to say that there is no magic things to get the return value of each process. [see my answer here](https://stackoverflow.com/questions/26409877/cleaning-up-children-processes-asynchronously/46174954#46174954). It does not matter; you are using `bash` or `c` any others. you have to wait for any background process you have. and [see this one about wait in bash](https://stackoverflow.com/questions/1058047/wait-for-any-process-to-finish) – Shakiba Moshiri Sep 13 '17 at 10:24
  • I'm not an experienced Unix c programmer, but I know in principle how fork(), wait, SIGCHILD and zombie processes play together. I was hoping there would be a way to tell bash: "Wait for the next of the background processes to exit and give their exit code" (maybe what wait -n does). Or alternatively store the exit code into some variable. The real trouble is, that bash does not keep zombies, but immediately reaps them. So I have to run wait while the sub-process exits or I will miss the exit code... – TobiM Sep 13 '17 at 13:03
  • Found my mistake, thanks for the hepling pointers. – TobiM Sep 13 '17 at 14:08
  • `GNU Parallel is not an option`. Can you elaborate on that after reading http://oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html? – Ole Tange Sep 15 '17 at 06:41

1 Answers1

5

The answer is in How to wait in bash for several subprocesses to finish and return exit code !=0 when any subprocess ends with code !=0?

I was unaware that though the child is immediately reaped by bash, the builtin wait can still access the exit code for the pid.

#!/bin/bash

FAIL=0
PIDS=""

echo "starting"

sleep 5 &
PIDS="$PIDS $!"

sleep 3 &
PIDS="$PIDS $!"

/bin/false &
PIDS="$PIDS $!"

sleep 3 &
PIDS="$PIDS $!"

for job in $PIDS
do
    wait $job || let "FAIL+=1"
    echo $job $FAIL
done

echo $FAIL

if [ "$FAIL" == "0" ];
then
    echo "YAY!"
else
    echo "FAIL! ($FAIL)"
fi

correctly gives

starting
14772 0
14773 0
14774 1
14775 1
1
FAIL! (1)

Only the third process (/bin/false) fails, indicated by the switch from 0 to one in the third line.

TobiM
  • 151
  • 1
  • 8
  • 2
    When you want to store a list of items, consider using an array, not a string. This code is fragile -- as soon as `IFS` gets changed to a different value, `$PIDS` will no longer evaluated to your intended list. – Charles Duffy Sep 13 '17 at 14:55
  • (Also, avoid `==` in `[ ]` -- it's not guaranteed by the POSIX standard for `test` to work; the only mandated string comparison operator is `=`; see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html). – Charles Duffy Sep 13 '17 at 14:56
  • (Also, keep in mind that all-caps variable names are used by variables with the OS or shell, whereas lowercase names are reserved for application use, and thus guaranteed not to conflict; see relevant standard @ http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, fourth paragraph) – Charles Duffy Sep 13 '17 at 14:57