与GNU并行的“find”和“ls”

问题描述:

我试图使用GNU parallel将大量文件发布到Web服务器。在我的目录,我有一些文件:与GNU并行的“find”和“ls”

file1.xml 
file2.xml 

,我有一个shell脚本,看起来像这样:

#! /usr/bin/env bash 

CMD="curl -X POST [email protected]$1 http://server/path" 

eval $CMD 

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

ls | parallel -j2 script.sh {} 

这是什么GNU parallel页面显示为“正常”的方式在一个目录中的文件进行操作。这似乎是该文件的名称传递到我的剧本,但卷曲抱怨说,它无法加载传入的数据文件。然而,如果我这样做:

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

它工作正常。 lsfind是如何将参数传递给我的脚本的?或者我需要在脚本中做些额外的事情?

+1

您试过用#运行#!/ bin/bash -x会告诉你,如果你的论点不是你认为他们应该的。 –

+0

当这种情况发生时,我总是感到尴尬,但是当我第二天尝试重现此问题(并按照建议使用-x)时,我无法重现该问题,并且所有工作都很顺利。我已经能够使用ls或每次都能成功找到。我想知道如果我以某种方式填补了我的环境,并注销/清除了某些东西。 – Dave

我还没有使用parallel但在ls & find . -name '*.xml'之间有一个不同。 ls将列出全部的文件和目录,其中find . -name '*.xml'将只列出以.xml结尾的文件(和目录)。
正如Paul Rubel所建议的那样,只需在您的脚本中打印$ 1的值即可检查该值。此外,您可能需要考虑使用-type f选项将输入过滤到仅在find中的文件。
希望这有助于!

整洁。

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

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

另外,你上面提到的模式似乎并没有对我的并行工作,而我有 做到以下几点:

$ cat ../script.sh 
+ cat ../script.sh 
#!/bin/bash 
echo [email protected] 
$ 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 

查找确实提供了不同的输入,它预先给出了名称的相对路径。 也许这就是搞砸你的剧本?

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'将生成一个xml文件列表,以传递给script.sh程序。

> 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版本

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

更正确的变体将是如下:

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

然而,这并查找版本之间的重要区别是,发现将通过对文件的所有子目录的搜索,而ls只会搜索当前目录。等效find版本以上ls命令将如下所示:

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

这将只搜索当前目录。

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

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