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

AL-*_*teb 186 linux bash shell

我有一个看起来像这样的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
Run Code Online (Sandbox Code Playgroud)

但是处理每一行直到命令完成然后移动到下一行是非常耗时的,我想一次处理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
Run Code Online (Sandbox Code Playgroud)

当然,在这种情况下,我需要追加到行尾!但我觉得这不是正确的做法.

那么我如何实际将每20行组合在一起并等待它们完成,然后再转到接下来的20行,这个脚本是动态生成的,所以我可以在生成它的时候做我想要的任何数学运算,但它没有必要使用wget,这只是一个例子,所以任何特定于wget的解决方案都不会给我任何好处.

dev*_*ull 324

使用wait内置:

process1 &
process2 &
process3 &
process4 &
wait
process5 &
process6 &
process7 &
process8 &
wait
Run Code Online (Sandbox Code Playgroud)

对于上面的例子,4个进程process1... process4将在后台启动,shell将等到那些完成后才开始下一组.

GNU手册:

wait [jobspec or pid ...]
Run Code Online (Sandbox Code Playgroud)

等到每个进程ID pid或作业规范jobspec指定的子进程退出并返回等待的最后一个命令的退出状态.如果给出了作业规范,则等待作业中的所有进程.如果未给出参数,则等待所有当前活动的子进程,并且返回状态为零.如果jobspec和pid都没有指定shell的活动子进程,则返回状态为127.

  • 除非你确定每个过程都会在同一时间完成,否则这是一个坏主意.你需要启动新的工作来保持当前的总工作量达到一定的上限.... [parallel](http://stackoverflow.com/a/19543286/406281)就是答案. (16认同)
  • 所以基本上`i = 0; waitevery = 4; 对于"$ {links [@]}"中的链接; 做wget"$ link"&((i ++%waitevery == 0))&& wait; 完成>/dev/null 2>&1` (14认同)

cho*_*oba 93

并行.它的语法类似于xargs,但它并行运行命令.

  • 这比使用`wait`要好,因为它会像旧的一样完成新的工作,而不是在开始下一个工作之前等待整个批次完成. (12认同)
  • 例如,如果您有文件中的链接列表,则可以执行`cat list_of_links.txt | parallel -j 4 wget {}`这将保持四个`wget'一次运行. (5认同)
  • 镇上有一个叫做[pexec](https://www.gnu.org/software/pexec/)的新孩子,它取代了`parallel`. (5认同)
  • 不要挑剔,但xargs也可以并行化命令. (4认同)
  • 提供一个例子会更有帮助 (2认同)

小智 66

实际上,xargs 可以为您并行运行命令.有一个特殊的-P max_procs命令行选项.见man xargs.

  • +100 这很棒,因为它是内置的,使用起来非常简单,可以单线完成 (2认同)

小智 7

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

wait
Run Code Online (Sandbox Code Playgroud)

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