#!/usr/local/bin/bash
#
# 2004 Feb 15 jorgnsn
#
# Note that to work as intended, this script must be run using bash
# rather than ksh (sh == ksh, on IRIX) though it satisfies ksh syntax.
# The "wait" command in ksh seems to wait only for the child processes
# that existed when "wait" was called, while the "wait" command in
# bash waits for all child processes of the current process,
# including those created after "wait" was called. We need the latter
# behaviour in order to continue starting new children until the
# jobfile is exhausted.
#

USAGE="Usage: $0 jobfile jobsAtOnce"
#
# jobfile is the name of a file containing shell commands, one
# per line. 
#
# jobsAtOnce is an integer, greater than 0.
#
# Reads a list of shell commands, one per line, from a jobfile.
# Start the first jobsAtOnce jobs in the background, then continue to
# start more jobs as existing jobs exit.
#

set -m ## Job control required in order to be able to wait for SIGCHLD.

if test "$#" -lt 2
then
  echo $USAGE 1>&2
  exit 1
fi

jobfile="$1"
let jobsAtOnce=$2
if test "$2" -le 0
then
  echo "$jobsAtOnce must be greater than 0."
  exit 1
fi

let numJobs=0
while read line
do
  job[$numJobs]="$line"
  let numJobs=$numJobs+1
done < $jobfile

let jobsStarted=0

startJob() {
  if test "$jobsStarted" -lt "$numJobs"
  then
    command=${job[$jobsStarted]}
    let jobsStarted=$jobsStarted+1
    eval "$command" &
  fi
}

trap startJob CHLD  ## for each SIGCHLD received, start a new process.

while test $jobsStarted -lt $numJobs -a $jobsStarted -lt $jobsAtOnce
do
  startJob
done

wait  # for all jobs to finish
