我需要一个 bash 脚本来在后台运行一些作业,一次运行三个作业。
我知道可以通过以下方式做到这一点,为了说明,我假设作业数为 6:
./j1 &
./j2 &
./j3 &
wait
./j4 &
./j5 &
./j6 &
wait
但是,这样的话,例如,如果 j2 运行 j1 和 j3 需要更长的时间,那么,我将只能长时间运行一个后台作业。
备选方案(这是我想要的)是每当一个作业完成时,bash 应该启动队列中的下一个作业,以便在任何给定时间保持 3 个作业的速率。是否可以编写一个 bash 脚本来实现这个替代方案,可能使用循环?请注意,我需要运行更多的作业,我希望这种替代方法可以节省我很多时间。
这是我的脚本草稿,我希望你能帮助我验证它的正确性并改进它,因为我是 bash 脚本的新手。此脚本中的想法取自并修改自 here , here , 和 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
恕我直言,我认为此脚本执行所需的行为。但是,我需要从 bash 专家那里知道我是否做错了什么,或者是否有更好的方法来实现这个想法。
非常感谢。
最佳答案
使用 GNU xargs:
printf '%s\0' j{1..6} | xargs -0 -n1 -P3 sh -c './"$1"' _
使用 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
请注意,依赖内置函数的方法有一些极端情况——如果您有多个作业同时退出,单个 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
...这显然是一项繁重的工作,而且还有一场小比赛。考虑改用 xargs -P
。 :)
关于linux - bash 脚本在后台运行固定数量的作业,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42211173/