First try a simpler scenario such as only 2 processes FOO1 and FOO2, and if you were to run within a script for example named parent.sh:
#!/bin/bash
FOO1 &
pid1=$!
echo "Child PID=$pid1 launched"
FOO2 &
pid2=$!
echo "Child PID=$pid2 launched"
BAR exit FOO1
BAR exit FOO2
echo "Pausing to wait for children to finish..."
wait $pid1
wait $pid2
echo "Children finished, moving on."
See if this works with the two FOOs and if so, then implement for the 20.
Explanation
Since we are unable to see the internals of FOOs and BAR process, I am relying only on what you've posted and, as I understand it, you said
- "Process BAR is used to check FOO and is also used to kill it"
- meaning, at some point prior to your posted snippet, you started
FOO1 somehow, in order for BAR exit FOO1 to affect it
From among your originally posted snippet, you also wrote:
BAR exit FOO1
PID1=$!
$! captures the most recently background-ed process
- but
BAR exit FOO1 is not a process going into the background, it is as you claim, a means of using BAR to control FOO: "BAR is used to check FOO and is also used to kill it"
- thus
$! is unlikely to be capturing FOO1's pid
So instead, ensure that right where you actually start a FOO* process, you capture pid. For example if you are running all in parent.sh, and have only 2 processes, you would do:
#!/bin/sh
FOO1 &
pid1=$!
echo "Child PID=$pid1 launched"
FOO2 &
pid2=$!
echo "Child PID=$pid2 launched"
- lowercase
pid1, you can use your original uppercase too, as long as consistent, I just prefer to use lowercase as a convention to differentiate from being mistaken as environment variables
- The echo is an optional trace so we know what is going on, use it while we are troubleshooting and comment it out with
# or delete it once you've solved this problem
We then do the commands you claimed you use to check and kill FOO1 and FOO2:
BAR exit FOO1
BAR exit FOO2
Then,
echo "Pausing to wait for children to finish..."
wait $pid1
wait $pid2
echo "Children finished, moving on."
- again the
echos are optional but informative while you are still troubleshooting this, lets us know what is happening
wait for each individual $pid...
- followed by another optional
echo to let you know the waiting is over
CREDIT
Shotts 2009 asynchronous scripts example on the free pdf's page 506
waitand$!constructs are shell tools for controlling jobs / processes your shell spawns. In your description, the only process your shell spawns isBAR, and by your description,BARexits immediately after spawning some opaque background stuff. Your shell can't see that background stuffBARdoes, onlyBAR, so it doesn't even have any background jobs / processes to usewait/$!on. If you need a mechanism to know whether the internal background process spawned byBAR exit FOO1worked, it has to come fromBAR.cgroupszoo was created in Linux (in part at least) to be able to solve exactly this kind of problem cleanly. There is no simple, clean solution to this problem.