与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 {}
它工作正常。 ls
和find
是如何将参数传递给我的脚本的?或者我需要在脚本中做些额外的事情?
我还没有使用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 parallel
是xargs
的变体。他们都有非常相似的界面,如果您在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字符来标记每个参数。
请注意,parallel
比xargs
稍好一点,因为它的默认行为是仅围绕换行符的标记化,所以不需要更改默认行为。
另一个常见问题是您可能想要控制参数如何传递到xargs
或parallel
。如果您需要传递给程序的参数的特定位置,则可以使用{}
来指定参数放置的位置。
> 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
所以考虑到如何xargs
和parallel
工作,你应该希望能够看到问题与你的命令。 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
您试过用#运行#!/ bin/bash -x会告诉你,如果你的论点不是你认为他们应该的。 –
当这种情况发生时,我总是感到尴尬,但是当我第二天尝试重现此问题(并按照建议使用-x)时,我无法重现该问题,并且所有工作都很顺利。我已经能够使用ls或每次都能成功找到。我想知道如果我以某种方式填补了我的环境,并注销/清除了某些东西。 – Dave