I'm writing a bash script that spawns a number of background processes. I'd like to be notified whenever a process terminates; and I would like to know the pid of the terminated process.
I have looked at using wait
, such that the pids of each spawned process are captured and stored in an array, and then the array is iterated over, and wait is called on each process. This technique is described in various ways here:
https://stackoverflow.com/a/356154/366856
The problem with this, if I understand it correctly, is that it can be relatively inefficient if you want to perform some action as soon as an individual process terminates. For example, if you spawn processes A and B, and B finishes before A, then execution must wait for both A and B to finish. I need to perform an action as soon as B finishes.
It seems trap SIGCHLD
is the way to perform an action immediately when a child terminates, but the problem is that I cannot find a way to determine the pid of the the source of the SIGCHLD signal, which I also need. The closest thing I've found to a working example of this is the third code example in this post:
http://www.linuxforums.org/forum/programming-scripting/103996-multithreading-bash.html#post510187
I've copy-pasted it here for convenience:
#!/bin/bash
iNext=0
function ChildReturned() {
wait $1
echo "$1 was returned. Its exits status was: $?"
iNext=$((iNext+1))
StartChild $iNext
}
function StartChild {
./child $1 &
pid=$!
echo "Started: $1 PID= $pid"
trap 'ChildReturned $pid' SIGCHLD
}
set -bm
for (( iNext=0; iNext<=10; iNext++ ));
do
StartChild $iNext
done
wait
I think this example doesn't work, because the author makes the mistake of calling trap
multiple times, each time capturing a different pid variable in trap
's argument. Each time trap is called, it overwrites the previous call, and thus an arbitrary pid will be captured. I haven't been able to find a better technique.
Is there a way to get the pid of a terminated child process using trap in bash?
Update
I just wanted to point to this resource, which contains the best, most comprehensive overview of solutions to this problem that I have seen thus far:
http://mywiki.wooledge.org/ProcessManagement#I_want_to_process_a_bunch_of_files_in_parallel.2C_and_when_one_finishes.2C_I_want_to_start_the_next._And_I_want_to_make_sure_there_are_exactly_5_jobs_running_at_a_time.
Set the trap once, and in the trap you can call jobs -n
to see which children have finished since you last checked. Note that this doesn't tell you which child sent the SIGCHLD; consider the case where two children die before you enter the trap. In that case, you will only enter the trap once, and it is a moot point which child's signal you are actually responding to. Note that -n
is a bash extension, and you might prefer to use jobs -l
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With