运行后台(异步)命令并同步输出

运行后台(异步)命令并同步输出

我正在使用 curl 获取 URL 然后写入文件,如下所示:

urls=( 
  'https://www.example1.com'
  'https://www.example2.com'
 )

for i in ${urls[@]}; do
   curl $i &
done
echo 'stuff'

我故意简化了代码,以便可以解决确切的问题。

输出:

stuff
$curlContents1
$curlContents2

我知道为什么会发生这种情况,它是异步运行的。

我想知道

  • 我希望运行这个异步 cmd,并且其输出与同步运行的输出相同。
  • 这是因为异步运行可以大大提高速度

期望输出:

$curlContents1
$curlContents2
stuff

更多信息

  • 我的实际问题有点不同……

我正在做的是下载视频,然后获取 URL 的最后一部分并将其用作文件名,parallel在此示例中我该如何使用?

写入发生在下载之前,因为下载是最耗时的部分

arr=(
  'https://www.example1.com/stccdtu.mp4’
  'https://www.example2.com/dyubdf.mp4’
 )

for i in ${arr[@]}; do 
    curl $i > `echo $i | sed s'#https://www.example[0-9].com/##'g` &
done

输出:

ll

0 stccdtu.mp4 
0 dyubdf.mp4

答案1

使用 GNU parallel。基本示例:

parallel -j 40 --group --keep-order curl ::: "${urls[@]}"
echo 'stuff'

-j 40意味着我们分配了 40 个作业槽,即我们允许最多 40 个并行作业(根据您的需求和能力进行调整)。如果您提供更多 URL,则在某个槽可用后将处理第 41 个 URL。所有 URL 都将被处理,但任何时候最多会有 40 个作业并行运行。

使用的其他选项:

--group
分组输出。每个作业的输出被分组在一起,并且仅在命令完成时打印。首先是 Stdout(标准输出),然后是 stderr(标准错误)。[…]

来源

这是默认设置,因此通常您不必明确使用它。

--keep-order
-k
保持输出顺序与输入顺序一致。通常,作业完成后会立即打印输出。[…]-k仅影响打印输出的顺序 - 而不影响运行作业的顺序。

来源

笔记:

  • 在我的示例中,parallel它不在后台运行,而是同步运行(因此echo在它之后运行);仍然curl并行、异步运行。

  • 在 Debian GNU 中,parallel有一个名为 的包parallel。该工具的基本变体(moreutils至少来自 )在 Debian 中) 的威力较小。

  • parallel是一个外部命令。如果数组足够大,那么parallel … ::: "${urls[@]}"你将命中argument list too long. 改用这个:

    printf '%s\n' "${urls[@]}" | parallel …
    

    它会起作用是因为 Bashprintf是一个内置函数,因此之前的所有操作|都由 Bash 内部处理。

  • ${urls[@]}正确双引号(在您的代码中${urls[@]}并且$i没有引用,这是错误的)。


GNUparallel 可以调用导出的 Bash 函数。这使我们能够解决您所说的实际问题:

getvideo() {
curl "$1" > "${1##*/}"
}
export -f getvideo

urls=(
  'https://www.example1.com/stccdtu.mp4'
  'https://www.example2.com/dyubdf.mp4'
 )

parallel -j 40 --group --keep-order getvideo ::: "${urls[@]}"
echo 'stuff'

如果你不知道该怎么${1##*/}做,请阅读这是我的另一个答案

答案2

Bash shell 有一个wait命令,它会暂停脚本,直到后台作业完成。

等待每个由 ID 标识的进程(该 ID 可能是进程 ID 或作业规范),并报告其终止状态。 如果身份证没有 给定,等待所有当前活动的子进程,返回状态为零。如果 ID 是作业规范,则等待该作业管道中的所有进程。

for i in ${urls[@]}; do
   curl $i &
done
wait
echo 'stuff'

相关内容