Bash脚本并行处理有限数量的命令


196

我有一个bash脚本,如下所示:

#!/bin/bash
wget LINK1 >/dev/null 2>&1
wget LINK2 >/dev/null 2>&1
wget LINK3 >/dev/null 2>&1
wget LINK4 >/dev/null 2>&1
# ..
# ..
wget LINK4000 >/dev/null 2>&1

但是处理每一行直到命令完成然后转移到下一行非常耗时,我想一次处理例如20行,然后当它们完成时再处理另外20行。

我曾考虑过wget LINK1 >/dev/null 2>&1 &将命令发送到后台并继续执行,但是这里有4000行,这意味着我将遇到性能问题,更不用说受限于我应该同时启动多少个进程,所以这不是一个好选择理念。

我现在正在考虑的一种解决方案是检查其中一个命令是否仍在运行,例如,在20行之后,我可以添加以下循环:

while [  $(ps -ef | grep KEYWORD | grep -v grep | wc -l) -gt 0 ]; do
sleep 1
done

当然,在这种情况下,我需要在行的末尾添加&!但是我感觉这不是正确的方法。

因此,我实际上如何将每20行分组在一起并等待它们完成,然后再转到下20行,该脚本是动态生成的,因此我可以在生成脚本时对其进行所需的任何数学运算,但不必使用wget,这只是一个示例,因此任何特定于wget的解决方案都不会给我带来任何好处。


1
wait是这里的正确答案,但是使用proctoolswhile [ $(ps …会更好得多……也就是说,出于正当理由,请检查具有特定名称的进程是否仍在运行。while pkill -0 $KEYWORD…
kojiro

我认为这个问题应该重新讨论。“可能重复”的质量检查就是关于并行运行有限数量的程序。像2-3个命令。但是,这个问题集中在例如循环中运行命令。(请参阅“但有4000行”)。
VasiliNovikov

@VasyaNovikov您是否已阅读 有关此问题和重复项的所有答案?在此,每个问题的答案也可以在重复问题的答案中找到。这正是重复问题的定义。是否循环运行命令绝对没有区别。
robinCTS

@robinCTS有交叉点,但是问题本身是不同的。此外,链接的质量检查中最受欢迎的6个答案仅涉及2个过程。
VasiliNovikov

2
我建议重新打开该问题,因为它比链接的问题的答案更清晰,更干净,更好,而且被更高程度地支持,尽管它是最近三年了。
Dan Nissenbaum '18

Answers:


331

使用wait内置的:

process1 &
process2 &
process3 &
process4 &
wait
process5 &
process6 &
process7 &
process8 &
wait

对于上面的例子中,4个进程process1...... process4将在后台启动,并在外壳会等到这些都开始下一组之前完成。

GNU手册

wait [jobspec or pid ...]

等待直到由每个进程ID pid或作业规范jobspec指定的子进程退出,并返回等待的最后一条命令的退出状态。如果给出了作业说明,则将等待作业中的所有过程。如果未提供任何参数,则将等待所有当前活动的子进程,并且返回状态为零。如果jobspec和pid均未指定外壳的活动子进程,则返回状态为127。


14
所以基本上i=0; waitevery=4; for link in "${links[@]}"; do wget "$link" & (( i++%waitevery==0 )) && wait; done >/dev/null 2>&1
kojiro

18
除非您确定每个过程都将在同一时间完成,否则这是个坏主意。您需要启动新作业,以将当前的总作业数保持在一定的上限.. 并行是答案。
rsaw 2014年

1
有没有办法做到这一点循环?
DomainsFeatured'Sep

我已经尝试过了,但是似乎在一个块中完成的变量分配在下一个块中不可用。这是因为它们是分开的过程吗?有没有办法将变量传达回主流程?
Bobby

97

参见parallel。它的语法类似于xargs,但是它并行运行命令。


13
这比使用更好wait,因为它会在旧工作完成时开始新工作,而不是等待整个批处理完成之后再开始下一个工作。
chepner 2013年

5
例如,如果您在文件中具有链接列表,则可以这样做cat list_of_links.txt | parallel -j 4 wget {},一次保持四个wgets运行。
骆马先生2015年

5
镇上有个叫pexec的新孩子,可以代替parallel
slashsbin 2015年

2
提供示例会更有用
jterm

1
parallel --jobs 4 < list_of_commands.sh,其中list_of_commands.sh是每行带有单个命令(例如wget LINK1,不带的注释&)的文件。可能需要做CTRL+Zbg后把它留在后台运行。
weiji 14


7

您可以运行20个进程并使用以下命令:

wait

当所有后台作业完成后,脚本将等待并继续。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.