GNU Parallel用于并行化for循环。

9

我看到了许多关于这个主题的问题,但我缺乏将其翻译成我的具体问题的能力。 我有一个for循环,可以循环遍历子目录,然后在每个目录中执行压缩的文本文件上的.sh脚本。 我想并行化这个过程,但我无法应用gnu parallel。

这是我的循环:

for d in ./*/ ; do (cd "$d" && script.sh); done

我理解需要将列表输入到并行处理中,因此我一直在尝试这样做:

ls -d */ | parallel cd && script.sh

虽然看起来开始了,但当gzip尝试解压目录中的一个txt文件时,出现了错误,说文件不存在:

gzip: *.txt.gz: No such file or directory

然而,当我运行原始的for循环时,除了需要很长时间才能完成之外,我没有遇到任何问题。此外,只有在使用Parallel时,我才会遇到gzip错误一次,这太奇怪了,考虑到我有1000多个子目录。

我的问题是:

  1. 如何让Parallel在我的情况下工作?如何使parallel化一个.sh脚本应用于它们自己的子目录中的数千个文件?即-什么是解决我的问题的解决方案?我必须取得进展。

  2. 我错过了什么?语法、循环、坏脚本?我想学习。

  3. Parallel是否实际上尝试并行运行所有这些.sh脚本?为什么我不会为每个.txt.gz文件收到错误?

  4. Parallel是应用的最佳选择吗?是否有另一个更适合我的需求的选项?

1个回答

17
两个问题:
在: ls -d */ | parallel cd && script.sh
并行的是只有cd,而不是script.sh。只有在所有parallel cd任务运行完毕且没有错误时,script.sh才会执行一次。这与以下情况相同:
    ls -d */ | parallel cd
    if [ $? -eq 0 ]; then script.sh; fi

您没有将目标目录传递给cd。因此,由parallel执行的只是cd,它仅将当前目录更改为您的主目录。最终的script.sh在当前目录(从您调用命令的位置)中执行,那里可能没有*.txt.gz文件,因此会出现错误。
您可以通过以下方式自行检查第一个问题的影响:
$ mkdir /tmp/foobar/{a..c} && cd /tmp/foobar
$ ls -d */ | parallel cd && pwd
/tmp/foobar
pwd 的输出只会打印一次,即使你有多个输入目录。你可以通过引用命令来修复它,然后使用以下命令检查第二个问题:
$ ls -d */ | parallel 'cd && pwd'
/homes/myself
/homes/myself
/homes/myself

你应该看到与输入目录数量相同的pwd输出,但始终是相同的输出:你的主目录。你可以通过使用“{}”替换字符串来解决第二个问题,该字符串将被当前输入替换。用以下方式检查它:
$ ls -d */ | parallel 'cd {} && pwd'
/tmp/foobar/a
/tmp/foobar/b
/tmp/foobar/c

现在,你应该在输出中正确列出所有的输入目录。
对于你的具体问题,这个方法应该有效:
ls -d */ | parallel 'cd {} && script.sh'

1
讲解得很好! - Mark Setchell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接