我正在使用 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 …
它会起作用是因为 Bash
printf
是一个内置函数,因此之前的所有操作|
都由 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'