使用 GNU Parallel 运行时,Bash 脚本“while read”循环会导致“管道损坏”错误

使用 GNU Parallel 运行时,Bash 脚本“while read”循环会导致“管道损坏”错误

根据 GNU Parallel 邮件列表,这不是 GNU Parallel 特有的问题。他们建议我在这里发布我的问题。

我收到的错误是“管道损坏”错误,但我觉得我应该先解释一下我的问题背景以及导致此错误的原因。在 GNU Parallel 中尝试使用任何包含“while read”循环的 bash 脚本时,就会发生这种情况。

我有一个像这样的基本 bash 脚本:

#!/bin/bash
# linkcheck.sh

while read domain
do
host "$domain"
done

假设我想要导入一个大列表(比如说 250mb)。

cat urllist | ./linkcheck.sh

在 250mb 大小的 URL 上运行 host 命令相当慢。为了加快速度,我想在管道传输之前将输入拆分成块,然后并行运行多个作业。GNU Parallel 可以做到这一点。

cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}

{} 逐行替换为 urllist 的内容。假设我的系统默认设置能够在每个并行实例中运行 500 个作业。为了绕过这个限制,我们可以并行化 Parallel 本身:

cat urllist | parallel -j10 --pipe parallel -j0 ./linkcheck.sh {}

这将运行 5000 个作业。不幸的是,它还会导致错误“管道损坏”(bash 常见问题解答)。但是,如果我删除 while read 循环并直接从输入到 {} 的任何内容中获取输入,脚本就会开始工作,例如,

#!/bin/bash
# linkchecker.sh

domain="$1"
host "$1"

为什么它不能与 while read 循环一起使用?关闭 SIGPIPE 信号以停止“管道损坏”消息是否安全,或者是否会产生诸如数据损坏之类的副作用?

谢谢阅读。

答案1

那么,

cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}

工作正常吗?我认为你的问题部分可能是你漏掉了第二个--pipe,比如

cat urllist | parallel -j10 --pipe parallel -j0- 管道./linkcheck.sh {}

 


顺便说一句,你永远不需要说

一个文件|一些命令

您可以随时将其更改为

一些命令<一个文件

从而减少一个进程(并减少一个管道)。 (cat当您有多个输入文件时,使用它可能是适当/必要的。)

答案2

在我看来,错误可能是由于竞争条件不良而引起的,因为在管道仍处于打开状态时,分叉子进程运行 linkcheck.sh 的另一个副本与子进程实际尝试读取之间的时间窗口。在该窗口中,另一个副本已读取 EOF 并且管道已关闭。

相关内容