GNU并行“find”和“ls”

时间:2011-09-30 12:41:55

标签: linux bash parallel-processing find gnu-parallel

我正在尝试使用GNU parallel将大量文件发布到Web服务器。在我的目录中,我有一些文件:

file1.xml
file2.xml

我有一个shell脚本,如下所示:

#! /usr/bin/env bash

CMD="curl -X POST -d@$1 http://server/path"

eval $CMD

脚本中还有其他一些东西,但这是最简单的例子。我试图执行以下命令:

ls | parallel -j2 script.sh {}

GNU parallel页面显示的是对目录中文件进行操作的“正常”方式。这似乎将文件的名称传递给我的脚本,但curl抱怨它无法加载传入的数据文件。但是,如果我这样做:

find . -name '*.xml' | parallel -j2 script.sh {}

它工作正常。 lsfind如何将参数传递给我的脚本之间有区别吗?或者我是否需要在该脚本中做一些额外的事情?

4 个答案:

答案 0 :(得分:6)

GNU parallelxargs的变体。他们都有非常相似的界面,如果你在parallel寻求帮助,你可能会更幸运地查找有关xargs的信息。

话虽如此,他们的运作方式相当简单。使用默认行为,两个程序都从STDIN读取输入,然后根据空格将输入分解为标记。然后将这些标记中的每一个作为参数传递给提供的程序。 xargs的默认值是将尽可能多的令牌传递给程序,然后在达到限制时启动新进程。我不确定并行的默认值是如何工作的。

以下是一个例子:

> echo "foo    bar \
  baz" | xargs echo
foo bar baz

默认行为存在一些问题,因此通常会看到多种变体。

第一个问题是因为空格用于标记化,所以任何包含空格的文件都会导致并行和xargs中断。一种解决方案是改为使用NULL字符进行标记。 find甚至提供了一个让这很容易做到的选项:

> echo "Success!" > bad\ filename
> find . "bad\ filename" -print0 | xargs -0 cat
Success!

-print0选项告诉find使用NULL字符而不是空格分隔文件。
-0选项告诉xargs使用NULL字符来标记每个参数。

请注意,parallelxargs好一点,因为它的默认行为是仅围绕换行的标记,因此不需要更改默认行为。

另一个常见问题是您可能希望控制参数传递给xargsparallel的方式。如果需要传递给程序的参数的特定位置,可以使用{}指定参数的放置位置。

> mkdir new_dir
> find -name *.xml | xargs mv {} new_dir

这会将当前目录和子目录中的所有文件移动到new_dir目录中。它实际上分解为以下几点:

> find -name *.xml | xargs echo mv {} new_dir
> mv foo.xml new_dir
> mv bar.xml new_dir
> mv baz.xml new_dir

因此,考虑到xargsparallel的工作原理,您应该能够看到命令的问题。 find . -name '*.xml'将生成要传递给script.sh程序的xml文件列表。

> find . -name '*.xml' | parallel -j2 echo script.sh {}
> script.sh foo.xml
> script.sh bar.xml
> script.sh baz.xml

但是,ls | parallel -j2 script.sh {}将生成当前目录中要传递给script.sh程序的所有文件的列表。

> ls | parallel -j2 echo script.sh {}
> script.sh some_directory
> script.sh some_file
> script.sh foo.xml
> ...

ls版本的更正确的变体如下:

> ls *.xml | parallel -j2 script.sh {}

然而,这与find版本的重要区别在于find将在所有子目录中搜索文件,而ls只搜索当前目录。上述find命令的等效ls版本如下:

> find -maxdepth 1 -name '*.xml'

这只会搜索当前目录。

答案 1 :(得分:3)

由于它适用于find,您可能希望查看GNU Parallel正在运行的命令(使用-v或--dryrun),然后尝试手动运行失败的命令。

ls *.xml | parallel --dryrun -j2 script.sh
find -maxdepth 1 -name '*.xml' | parallel --dryrun -j2 script.sh

答案 2 :(得分:2)

我没有使用parallel,但lsfind . -name '*.xml'之间存在差异。 lsfind . -name '*.xml'将列出所有文件和目录,其中find将仅列出以 .xml 结尾的文件(和目录)。<登记/> 正如Paul Rubel所建议的,只需在脚本中打印$ 1的值即可检查。此外,您可能需要考虑仅使用-type f选项在{{1}}中过滤输入文件 希望这有帮助!

答案 3 :(得分:1)

纯。

之前从未使用过平行线。看起来虽然有两个。 一个是Gnu Parrallel,我系统上安装的那个有Tollef Fog Heen 在手册页中列为作者。

正如保罗所说,你应该使用    设置-x

另外,你上面提到的范例似乎并不适用于我的并行,而是,我有 做以下事情:

$ cat ../script.sh
+ cat ../script.sh
#!/bin/bash
echo $@
$ parallel -ij2 ../script.sh {} -- $(find -name '*.xml')
++ find -name '*.xml'
+ parallel -ij2 ../script.sh '{}' -- ./b.xml ./c.xml ./a.xml ./d.xml ./e.xml
./c.xml
./b.xml
./d.xml
./a.xml
./e.xml
$ parallel -ij2 ../script.sh {} -- $(ls *.xml)
++ ls --color=auto a.xml b.xml c.xml d.xml e.xml
+ parallel -ij2 ../script.sh '{}' -- a.xml b.xml c.xml d.xml e.xml
b.xml
a.xml
d.xml
c.xml
e.xml

find确实提供了不同的输入,它预先设定了名称的相对路径。 也许这就是弄乱你的剧本?