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

我需要一个bash脚本来在后台运行一些工作,一次三个工作。

我知道可以这样做,为了说明,我将假定工作的数量是6:

./j1 & ./j2 & ./j3 & wait ./j4 & ./j5 & ./j6 & wait 

然而,这样一来,如果j2花费了很多时间来运行j1和j3,那么我就只能被一个长时间运行的后台作业卡住了。

另一种方式(我想要的)是每当一个工作完成时,bash应该启动队列中的下一个工作,以便在任何给定时间保持3个工作的比率。 是否有可能编写一个bash脚本来实现这个select,可能使用循环? 请注意,我需要运行更多的工作,我希望这种替代方法能为我节省很多时间。

这是我的脚本草稿,我希望你能帮助我validation它的正确性,并改进它,因为我对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 

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

非常感谢你。

使用GNU xargs:

 printf '%s\0' j{1..6} | xargs -0 -n1 -P3 sh -c './"$1"' _ 

随着bash(4.x)builtins:

 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来代替。 🙂

使用GNU并行:

 parallel -j3 ::: ./j{1..6} 

或者如果你的shell不这样做..扩展(例如csh):

 seq 6 | parallel -j3 ./j'{}' 

如果您认为无法安装GNU Parallel,请阅读http://oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html,并留下评论为什么您无法安装它&#x3002;

也许这可能有助于..

示例用例 :运行“睡眠20”30次,就如同一个例子。 它可以是任何工作或其他脚本。 我们的控制逻辑是不断检查“有多少已经被解雇?” 小于或等于“最大进程定义”,在while循环中。 如果没有,就开一个,如果是的话,睡5秒。

脚本输出:在下面的snip中,现在我们有30个'sleep 20'命令在后台运行,我们配置了max = 30。

 %_Host@User> ps -ef|grep 'sleep 20'|grep -v grep|wc -l 30 %_Host@User> 

更改no的值。 运行时的作业 :脚本有一个参数“max”,它从文件“max.txt”( max=$(cat max.txt) )中获取值,然后在while循环的每次迭代中应用它。 如下所示,我们将其更改为45,现在我们有45个“sleep 20”命令在后台运行。 你可以把主脚本放在后台,只要改变“ max.txt ”中的最大值来控制即可。

 %_Host@User> cat > max.txt 45 ^C %_Host@User> ps -ef|grep 'sleep 20'|grep -v grep|wc -l 45 %_Host@User> 

脚本:

 #!/bin/bash #---------------------------------------------------------------------# proc='sleep 20' # Your process or script or anything.. max=$(cat max.txt) # configure how many jobs do you want curr=0 #---------------------------------------------------------------------# while true do curr=$(ps -ef|grep "$proc"|grep -v grep|wc -l); max=$(cat max.txt) while [[ $curr -lt $max ]] do ${proc} & # Sending process to background. max=$(cat max.txt) # After sending one job, again calculate max and curr curr=$(ps -ef|grep "$proc"|grep -v grep|wc -l) done sleep .5 # sleep .5 seconds if reached max jobs. done #---------------------------------------------------------------------# 

让我们知道这是否有用。