如何使用tollef parallel并行多次并行运行脚本

时间:2014-04-14 02:52:18

标签: bash shell parallel-processing

假设我有一个脚本,它不接收任何参数并输出一些内容给stdout。我想像这样执行它

 php script.php >> output.txt

我的Ubuntu 12.04 LTS机器上安装了parallel程序。我认为这不是GNU并行,因为手册与GNU parallel的不同。

使用parallel程序,我可以这样做

$parallel -j 4 -- 'php script.php >> output.txt' 'php script.php >> output.txt' 'php script.php >> output.txt' 'php script.php >> output.txt' 'php script.php >> output.txt'

它基本上运行4个并行作业中的所有'php script.php >> output.txt'命令。

假设我想要运行脚本100次。我尝试使用bash for loop。

commands=''; for i in {1..100}; do commands+=" 'php script.php >> output.txt'"; done; parallel -j 4 -- `echo $commands`

但它会返回很多错误。

sh: 1: sh: 1: Syntax error: Unterminated quoted string
Syntax error: end of file unexpected
sh: 1: script.php: not found
sh: 1: Syntax error: Unterminated quoted string
sh: 1: Syntax error: Unterminated quoted string
sh: 1: script.php: not found
sh: 1: Syntax error: end of file unexpected
sh: 1: Syntax error: Unterminated quoted string
sh: 1: Syntax error: Unterminated quoted string
sh: 1: sh: 1: Syntax error: end of file unexpected
sh: 1: Syntax error: Unterminated quoted string
sh: 1: Syntax error: Unterminated quoted string
script.php: not found

但是当我将$commands输出到屏幕(echo $commands)并附加到parallel -j 4 --时,它会正常运行。

我哪里做错了?

3 个答案:

答案 0 :(得分:4)

我知道你没有安装GNU Parallel,但如果你有,你可以这样做:

seq 4 | parallel -N0 -j 4 php script.php >> output

-N0 =不附加参数。

您还可以通过将多个命令并行附加到同一文件来避免存在的竞争条件。

答案 1 :(得分:1)

这是一个单词分裂问题 - $command中的引号被视为字面而不是语法。以下是这种情况的一个例子:

$ ls
file1  script
$ foo="'file1' 'script'"
$ echo foo
'file1' 'script'
$ cat $foo
cat: 'file1': No such file or directory
cat: 'script': No such file or directory

单引号被视为文字。因此,在您的问题中,不是并行传递命令'php script.php >> output.txt',而是传递'php,然后传递script.php等。引用变量不会有帮助,因为它会然后将所有100个命令视为一个单词。

您应该能够使用数组来避免这种情况:

commands=(); 
for i in {1..100}; do 
    commands[$i]=" 'php script.php >> output.txt'"
done; 
parallel -j 4 -- "${commands[@]}"

答案 2 :(得分:1)

经过多次试验,我发现我可以为parallel执行的命令设置虚假参数。

通过重读手册,我发现有两种方法可以使用parallel

parallel [options] [command] -- [argument ...]
parallel [options] -- [command ...]

除了使用它之外(如我的问题所示)

$parallel -j 4 -- 'php script.php >> output.txt' 'php script.php >> output.txt' 'php script.php >> output.txt' 'php script.php >> output.txt' 'php script.php >> output.txt'

我也可以这样做

$parallel -j 4 php script.php >> output.txt -- 1 2 3 4 5

由于php script.php >> output.txt1 2 3 4 5将执行5次。文本1 2 3 4 5将作为参数,但由于命令没有接收参数,它仍将被执行5次。

所以最后的命令就是这样。

args=''
for i in {1..100}; do
    args+=' $i';
done;
parallel -j 4 php script.php >> output.txt -- $args

我试过这个,它有效

petra@petra-laptop:~$ args=''; for i in {1..100}; do args+=' $i'; done; parallel -j 4 php script.php >> output.txt -- $args
petra@petra-laptop:~$ wc -l output.txt 
100 output.txt

更短

petra@petra-laptop:~$ rm output.txt 
petra@petra-laptop:~$ parallel -j 4 php script.php >> output.txt -- `for i in {1..100}; do echo $i; done;`
petra@petra-laptop:~$ wc -l output.txt 
100 output.txt