how to a Write a script that runs a 5 instances of a child process in the background (at a gap of 5 seconds) and do a continuous check to see if any of the child process is completed it starts another instance of the same process till the child process has executed 20 instances.
Well I'm not entirely sure what you're asking but I'll do my best to guide you on the right path...
you can fork processes in your script like so:
/path/to/executable &
wait 5 seconds:
sleep 5
you can see how many instances of your program are currently running via ps:
ps aux | grep executable | wc -l
To keep track of how many instances have run, use a loop and an incrementing value:
#!/bin/bash
count = 0
while [ $count -lt 20 ]
do
if [ `ps aux | grep executable | wc -l` -lt 5 ]
then
/path/to/executable &
let "count += 1"
sleep 5
fi
done
the description is somewhat vague, I'm not sure if you want the 5 second gap to carry on for the subsequent 15 instances or not, and if you only want a max of 5 running at a time? That's how I interpreted it. There's many ways to implement this logic.
This should run in most POSIX-ish shells (I tested with dash (956b4bd… from Git), ksh (“1993-12-28 p” from Mac OS X 10.4), bash (2.05b and 4.0.35), zsh (4.3.10-dev-1; actually 8a04e94… from Git)):
#!/usr/bin/env dash
# usage: run-em <num> <num-simul> <start-gap> <executable> [<args ...]
test -n "$ZSH_VERSION" && setopt sh_word_split
pids=''
num="$1"
num_started=0
num_simul="$2"
start_gap="$3"
shift 3
poll_gap=1 # polling interval
while test "$num_started" -lt "$num" ||
test -n "$pids"; do
alive_pids=''
for pid in $pids; do
if kill -0 "$pid" > /dev/null 2>&1; then
alive_pids="$pid
$alive_pids"
else
printf 'PID %s is gone\n' "$pid" 1>&2
fi
done
pids="$alive_pids"
new_pid=''
if test "$num_started" -lt "$num" &&
test "$(printf "$pids" | wc -l)" -lt "$num_simul"; then
exec 3>&1
new_pid="$("$@" 1>&3 3>&- & echo "$!")"
exec 3>&-
num_started="$((num_started+1))"
printf 'Started PID %s as #%s\n' "$new_pid" "$num_started" 1>&2
pids="$new_pid
$pids"
if test -n "$start_gap" &&
test "$num" -gt 0; then
printf 'Waiting %s seconds...' "$start_gap" 1>&2
sleep "$start_gap"
printf 'done\n' 1>&2
fi
fi
test -z "$start_gap$new_pid" && sleep "$poll_gap"
test "$num_started" -ge "$num_simul" && start_gap=''
done
Tested with: run-em 5 2 4 sh -c 'echo "[[$$ starting]]";sleep 13;echo "[[$$ ending]]"'
If you wanted to tie yourself to a particular shell, you might be able to use job control and a trap on SIGCHLD instead of double forking and probing with kill -0
(ksh and zsh seem capable of this, dash and bash seem broken for this; zsh also has a jobstates parameter that could be used to check for running jobs if SIGCHLD traps happened to be broken there). In some languages (e.g. Perl), you can use waitpid(2)
or wait4(2)
to wait for any child process so that you could collect their actual exit codes. Unfortunately, most shells seem to only let you wait for a specific child process, which would only work if you knew ahead of time which process was going to finish first.