bash脚本在后台运行一定数量的作业

use*_*439 5 linux bash shell

我需要一个bash脚本在后台运行一些作业,一次三个作业.

我知道可以通过以下方式做到这一点,为了说明,我假设工作的数量是6:

./j1 &
./j2 &
./j3 &
wait
./j4 &
./j5 &
./j6 &
wait
Run Code Online (Sandbox Code Playgroud)

但是,通过这种方式,例如,如果j2运行j1和j3需要更长的时间,那么,我将只会遇到一个运行很长时间的后台作业.

替代方案(这就是我想要的)是每当一个作业完成时,bash应该开始队列中的下一个作业,以便在任何给定时间保持3个作业的速率.是否可以编写一个bash脚本来实现这个替代方案,可能使用循环?请注意,我需要运行更多的工作,我希望这种替代方法能为我节省大量时间.

这是我的脚本草稿,我希望你可以帮助我验证它的正确性并改进它,因为我是bash脚本的新手.从这里,这里这里获取和修改此脚本中的想法:

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
Run Code Online (Sandbox Code Playgroud)

恕我直言,我认为这个脚本做了所需的行为.但是,我需要知道 - 来自bash专家 - 如果我做错了什么或者是否有更好的方法来实现这个想法.

非常感谢你.

Cha*_*ffy 5

使用GNU xargs:

printf '%s\0' j{1..6} | xargs -0 -n1 -P3 sh -c './"$1"' _
Run Code Online (Sandbox Code Playgroud)

使用bash(4.x)内置函数:

max_jobs=3; cur_jobs=0
for ((i=0; i<6; i++)); do
  # If true, wait until the next background job finishes to continue.
  ((cur_jobs >= max_jobs)) && wait -n
  # Increment the current number of jobs running.
  ./j"$i" & ((++cur_jobs))
done
wait
Run Code Online (Sandbox Code Playgroud)

请注意,依赖于内置函数的方法有一些极端的情况-如果您有多个作业恰好同时退出,那么一个作业wait -n可以收获其中的几个作业,从而有效地消耗了多个插槽。如果我们想变得更强大,可能会得到如下所示的结果:

max_jobs=3
declare -A cur_jobs=( ) # build an associative array w/ PIDs of jobs we started
for ((i=0; i<6; i++)); do
  if (( ${#cur_jobs[@]} >= max_jobs )); then
    wait -n # wait for at least one job to exit
    # ...and then remove any jobs that aren't running from the table
    for pid in "${!cur_jobs[@]}"; do
      kill -0 "$pid" 2>/dev/null && unset cur_jobs[$pid]
    done
  fi
  ./j"$i" & cur_jobs[$!]=1
done
wait
Run Code Online (Sandbox Code Playgroud)

...这显然是一项艰巨的工作,但仍需进行小范围比赛。考虑xargs -P改为使用。:)