Parallel bash with wait
20 August 2022
Parallel processing in bash is easy with the wait
command. There is a small gotcha to watch out for. To use it wait
will wait until all child background processes are finished. In your bash script you can toss a bunch of work into background processes with &
and instead of exiting, calling wait
will hang until they all complete:
#!/bin/bash
do_something() {
sleep 1
echo $1
}
for i in {1..5}; do
do_something $i &
done
wait
echo "All done!"
Running this will output something like this after 1 second, instead of the 5 seconds needed by each function.
5
1
3
2
4
All done!
The gotcha
Now the gotcha in that example has to do with handling error codes of the child processes. The difference is wait
vs wait $pid
.Waiting without a pid will swallow the exit code of the child process. Wait with a pid will return the exit code, so if we want to handle errors we will need to keep track of the pids of our child processes
The bash variable$!
holds the pid of the most recently created child process. Modifying our loop we can track the pids of each created process to an array:
for i in {1..5}; do
do_something "$i" &
pids+=($!)
done
And instead of waiting for all pids with wait
we wait for each pid individually, and track their exit codes in an array:
for pid in "${pids[@]}"; do
wait "${pid}"
status+=($?)
done
Putting this all together we now have parallel processing while handling exit codes of child processes:
#!/bin/bash
do_something() {
sleep 1
echo "$1"
exit $((i % 2))
}
for i in {1..5}; do
do_something "$i" &
pids+=($!)
done
for pid in "${pids[@]}"; do
wait "${pid}"
status+=($?)
done
for i in "${!status[@]}"; do
echo "job $i exited with ${status[$i]}"
done
echo "All done"
The output should look something like this, with the option of doing what you need on a per exit code basis:
1
5
4
3
2
job 0 exited with 1
job 1 exited with 0
job 2 exited with 1
job 3 exited with 0
job 4 exited with 1
All done