I need a bash script to run some jobs in the background, three jobs at a time.
I know can do this in the following way, and for illustration, I will assume the number of jobs is 6:
./j1 &
./j2 &
./j3 &
wait
./j4 &
./j5 &
./j6 &
wait
However, this way, if, for example, j2 takes a lot longer to run that j1 and j3, then, I will be stuck with only one background job running for a long time.
The alternative (which is what I want) is that whenever one job is completed, bash should start the next job in the queue so that a rate of 3 jobs at any given time is maintained. Is it possible to write a bash script to implement this alternative, possibly using a loop? Please note that I need to run far more jobs, and I expect this alternative method to save me a lot of time.
Here is my draft of the script, which I hope you can help me to verify its correctness and improve it, as I'm new to scripting in bash. The ideas in this script are taken and modified from here, here, and here):
for i in $(seq 6)
do
# wait here if the number of jobs is 3 (or more)
while (( (( $(jobs -p | wc -l) )) >= 3 ))
do
sleep 5 # check again after 5 seconds
done
jobs -x ./j$i &
done
wait
IMHO, I think this script does the required behavior. However, I need to know -from bash experts- if I'm doing something wrong or if there is a better way of implementing this idea.
Thank you very much.
Maybe this could assist..
Sample usecase: run 'sleep 20' 30 times, just as an example. It could be any job or another script. Our control logic is to keep checking whether "how many already fired?" is less than or equal to "max processes defined", inside a while loop. If not, fire one and if yes, sleep .5 seconds.
Script output: In the below snip, it is observed that now we have 30 'sleep 20' commands running in the background, as we configured max=30.
Change value of no. of jobs at runtime: Script has a param "max", which takes value from a file "max.txt"(
max=$(cat max.txt)
) and then applies it in each iteration of the while loop. As seen below, we changed it to 45 and now we have 45 'sleep 20' commands running in the background. You can put the main script in background and just keep changing the max value inside "max.txt
" to control.Script:
Let us know if it was any useful.
Using GNU Parallel:
Or if your shell does not do .. expansion (e.g. csh):
If you think you cannot install GNU Parallel, please read http://oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html and leave a comment on why you cannot install it.
With GNU xargs:
With bash (4.x) builtins:
Note that the approach relying on builtins has some corner cases -- if you have multiple jobs exiting at the exact same time, a single
wait -n
can reap several of them, thus effectively consuming multiple slots. If we wanted to be more robust, we might end up with something like the following:...which is obviously a lot of work, and still has a minor race. Consider using
xargs -P
instead. :)