欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

GNU Parallel的具体使用

程序员文章站 2023-03-25 20:13:35
它是什么? gnu parallel是一个shell工具,为了在一台或多台计算机上并行的执行计算任务,一个计算任务可以是一条shell命令或者一个以每一行做为输入的脚...

它是什么?

gnu parallel是一个shell工具,为了在一台或多台计算机上并行的执行计算任务,一个计算任务可以是一条shell命令或者一个以每一行做为输入的脚本程序。通常的输入是文件列表、主机列表、用户列表、url列表或者表格列表;一个计算任务也可以是一个从管道读取的一条命令。gnu parallel会把输入分块,然后通过管道并行的执行。

如果你会使用xargs和tee命令,你会发现gnu parallel非常易于使用,因为gnu parallel具有与xargs一样的选项。gnu parallel可以替代大部分的shell循环,并且用并行的方式更快的完成计算任务。

gnu parallel保证它的输出与顺序执行计算任务时是一样的,这样就可以方便的把gnu parallel的输出做为其它程序的输入。

对于每一行输入,gnu parallel会把这一行做为参数来运行指定的命令。如果没有给出命令,那么这一行会被当做命令执行。多行输入会并行的运行。gnu parallel经常被用于替代xargs或者cat | bash。

指南

本教程展示了绝大多数gnu parallel的功能。旨在介绍gnu parallel中的一个选项,而非讲解真实世界中使用的例子。花一个小时的时间学习本教程,你会由此爱上上命令行。

预备

为了执行本教程中的示例,你首先需要做如下准备:

parallel >= version 20130814

安装最新版:

(wget -o - pi.dk/3 || curl pi.dk/3/) | bash

这条命令同时也会安装最新版的指南

man parallel_tutorial

本教程的大部分内容同时也兼容旧版本。

abc-file

生成文件:

parallel -k echo ::: a b c > abc-file

def-file

生成文件:

parallel -k echo ::: d e f > def-file

abc0-file

生成文件:

perl -e 'printf "a\0b\0c\0"' > abc0-file

abc_-file

生成文件:

perl -e 'printf "a_b_c_"' > abc_-file

tsv_file.tsv

生成文件:

perl -e 'printf "f1\tf2\na\tb\nc\td\n"' > tsv-file.tsv

num30000

生成文件:

perl -e 'for(1..30000){print "$_\n"}' > num30000

num1000000

生成文件:

perl -e 'for(1..1000000){print "$_\n"}' > num1000000

num_%header

生成文件:

(echo %head1; echo %head2; perl -e 'for(1..10){print "$_\n"}') > num_%header

远程执行:ssh免密码登录$server1和$server2

生成文件:

server1=server.example.com
server2=server2.example.net

最后应该成功运行如下命令:

ssh $server1 echo works
ssh $server2 echo works

使用 ssh-keygen -t dsa; ssh-copy-id $server1 建立环境(使用empty pass phrase)

输入源

gnu parallel的输入源支持文件、命令行和标准输入(stdin或pipe)

单个输入源

从命令行读取输入:

parallel echo ::: a b c

输出(由于任务以并行的方式执行,顺序可能会有所不同):

a
b
c

文件做为输入源:

parallel -a abc-file echo

输出同上。

stdin(标准输入)做为输入源:

cat abc-file | parallel echo

输出同上。

多输入源

gnu parallel支持通过命令行指定多个输入源,它会生成所有的组合:

parallel echo ::: a b c ::: d e f

输出:

a d
a e
a f
b d
b e
b f
c d
c e
c f

多个文件做为输入源:

parallel -a abc-file -a def-file echo

输出同上。

stdin(标准输入)可以做为输入源中的一个,使用“-”:

cat abc-file | parallel -a - -a def-file echo

输出同上。

可以使用“::::”替代 -a:

cat abc-file | parallel echo :::: - def-file

输出同上。

::: 和 :::: 可以混合使用:

parallel echo ::: a b c :::: def-file

输出同上。

适配参数

–xapply 从每一个输入源取一个参数:

parallel --xapply echo ::: a b c ::: d e f

输出:

a d
b e
c f

如果其中一个输入源的长度比较短,它的值会被重复:

parallel --xapply echo ::: a b c d e ::: f g

输出:

a f
b g
c f
d g
e f

改变参数分隔符

gnu parallel可以指定分隔符替代 ::: 或 ::::,当这两个符号被其它命令占用的时候会特别有用:

parallel --arg-sep ,, echo ,, a b c :::: def-file

输出:

a d
a e
a f
b d
b e
b f
c d
c e
c f

改变参数分隔符:

parallel --arg-file-sep // echo ::: a b c // def-file

输出同上。

改变参数定界符

gnu parallel默认把一行做为一个参数:使用 \n 做为参数定界符。可以使用 -d 改变:

parallel -d _ echo :::: abc_-file

输出:

a
b
c

\0 代表null:

parallel -d '\0' echo :::: abc0-file

输出同上。

-0 是 -d '\0' 的简写(通常用于从 find … -print0读取输入):

parallel -0 echo :::: abc0-file

输出同上。

输入源中的结束值

gnu parallel支持指定一个值做为结束标志:

parallel -e stop echo ::: a b stop c d

输出:

a
b

跳过空行

使用 –no-run-if-empty 来跳过空行:

(echo 1; echo; echo 2) | parallel --no-run-if-empty echo

输出:

1
2

构建命令行

没有指定命令意味着参数就是命令

如果parallel之后没有给定命令,那么这些参数会被当做命令:

parallel ::: ls 'echo foo' pwd

输出:

[当前文件列表]
foo
[当前工作目录的路径]

命令可以是一个脚本文件,一个二进制可执行文件或一个bash的函数(须用 export -f 导出函数):

# only works in bash and only if $shell=.../bash
my_func() {
 echo in my_func $1
}
export -f my_func
parallel my_func ::: 1 2 3

输出:

in my_func 1
in my_func 2
in my_func 3

替换字符串

5种替换字符串

gnu parallel支持多种替换字符串。默认使用 {}:

parallel echo ::: a/b.c

输出:

a/b.c

指定 {} :

parallel echo {} ::: a/b.c

输出同上

去掉扩展名 {.}:

parallel echo {.} ::: a/b.c

输出

a/b

去掉路径 {/}:

parallel echo {/} ::: a/b.c

输出:

b.c

只保留路径 {//}:

parallel echo {//} ::: a/b.c

输出:

a

去掉路径和扩展名 {/.}:

parallel echo {/.} ::: a/b.c

输出:

b

输出任务编号:

parallel echo {#} ::: a/b.c

输出:

1
2
3

改变替换字符串

使用 -i 改变替换字符串符号 {}:

parallel -i ,, echo ,, ::: a/b.c

输出:

a/b.c

–extensionreplace替换 {.}:

parallel --extensionreplace ,, echo ,, ::: a/b.c

输出:

a/b

–basenamereplace替换 {/}:

parallel --basenamereplace ,, echo ,, ::: a/b.c

输出:

b.c

–dirnamereplace替换 {//}:

parallel --dirnamereplace ,, echo ,, ::: a/b.c

输出:

a

–basenameextensionreplace替换 {/.}:

parallel --basenameextensionreplace ,, echo ,, ::: a/b.c

输出:

b

–seqreplace替换 {#}:

parallel --seqreplace ,, echo ,, ::: a b c

输出:

1
2
3

指定位置替换字符串

如果有多个输入源时,可以通过 {编号} 指定某一个输入源的参数:

parallel echo {1} and {2} ::: a b ::: c d

输出:

a and c
a and d
b and c
b and d

可以使用 / // /. 和 .: 改变指定替换字符串:

parallel echo /={1/} //={1//} /.={1/.} .={1.} ::: a/b.c d/e.f

输出:

/=b.c //=a /.=b .=a/b
/=e.f //=d /.=e .=d/e

位置可以是负数,表示倒着数:

parallel echo 1={1} 2={2} 3={3} -1={-1} -2={-2} -3={-3} ::: a b ::: c d ::: e f

输出:

1=a 2=c 3=e -1=e -2=c -3=a
1=a 2=c 3=f -1=f -2=c -3=a
1=a 2=d 3=e -1=e -2=d -3=a
1=a 2=d 3=f -1=f -2=d -3=a
1=b 2=c 3=e -1=e -2=c -3=b
1=b 2=c 3=f -1=f -2=c -3=b
1=b 2=d 3=e -1=e -2=d -3=b
1=b 2=d 3=f -1=f -2=d -3=b

按列输入

使用 –colsep 把文件中的行切分为列,做为输入参数。下面使用tab(\t):

1=f1 2=f2
1=a 2=b
1=c 2=d

指定参数名

使用 –header 把每一行输入中的第一个值做为参数名:

parallel --header : echo f1={f1} f2={f2} ::: f1 a b ::: f2 c d

输出:

f1=a f2=c
f1=a f2=d
f1=b f2=c
f1=b f2=d

使用 –colsep 处理使用tab做为分隔符的文件:

parallel --header : --colsep '\t' echo f1={f1} f2={f2} :::: tsv-file.tsv

输出:

f1=a f2=b
f1=c f2=d

多参数

–xargs 让gnu parallel支持一行多个参数(可以指定上限):

cat num30000 | parallel --xargs echo | wc -l

输出:

2

30000个参数被分为两行。

一行中的参数个数的上限通过 -s 指定。下面指定最大长度是10000,会被分为17行:

cat num30000 | parallel --xargs -s 10000 echo | wc -l

为了获得更好的并发性,gnu parallel会在文件读取结束后再分发参数。

gnu parallel 在读取完最后一个参数之后,才开始第二个任务,此时会把所有的参数平均分配到4个任务(如果指定了4个任务)。

第一个任务与上面使用 –xargs 的例子一样,但是第二个任务会被平均的分成4个任务,最终一共5个任务。

cat num30000 | parallel --jobs 4 -m echo | wc -l

输出:

5

10分参数分配到4个任务可以看得更清晰:

parallel --jobs 4 -m echo ::: {1..10}

输出:

1 2 3
4 5 6
7 8 9
10

替换字符串可以是单词的一部分。通过下面两个命令体会 -m 和 -x 的区别:

parallel --jobs 4 -m echo pre-{}-post ::: a b c d e f g

输出:

pre-a b-post
pre-c d-post
pre-e f-post
pre-g-post

-x与 -m 相反:

parallel --jobs 4 -x echo pre-{}-post ::: a b c d e f g


输出:

pre-a-post pre-b-post
pre-c-post pre-d-post
pre-e-post pre-f-post
pre-g-post

使用 -n 限制每行参数的个数:

parallel -n3 echo ::: a b c d e f g h

输出:

a b c
d e f
g h

-n也可以用于指定位置替换字符串:

parallel -n3 echo 1={1} 2={2} 3={3} ::: a b c d e f g h

输出:

1=a 2=b 3=c
1=d 2=e 3=f
1=g 2=h 3=

-n0 只读取一个参数,但不附加:

parallel -n0 echo foo ::: 1 2 3

输出:

foo
foo
foo

引用

如果命令行中包含特殊字符,就需要使用引号保护起来。

perl脚本 'print “@argv\n”' 与linux的 echo 的功能一样。

perl -e 'print "@argv\n"' a

输出:

a

使用gnu parallel运行这条命令的时候,perl命令需要用引号包起来:

parallel perl -e 'print "@argv\n"' ::: this wont work

输出:

[nothing]

使用 -q 保护perl命令:

parallel -q perl -e 'print "@argv\n"' ::: this works

输出:

this
works

也可以使用 ' :

parallel perl -e \''print "@argv\n"'\' ::: this works, too

输出:

this
works,
too

使用 -quote:

parallel --shellquote
parallel: warning: input is read from the terminal. only experts do this on purpose. press ctrl-d to exit.
perl -e 'print "@argv\n"'
[ctrl-d]

输出:

perl\ -e\ \'print\ \"@argv\\n\"\'

也可以使用命令:

parallel perl\ -e\ \'print\ \"@argv\\n\"\' ::: this also works

输出:

this
also
works

去除空格

使用 –trim 去除参数两头的空格:

parallel --trim r echo pre-{}-post ::: ' a '

输出:

pre- a-post

删除左边的空格:

parallel --trim l echo pre-{}-post ::: ' a '

输出:

pre-a -post

删除两边的空格:

parallel --trim lr echo pre-{}-post ::: ' a '

输出:

pre-a-post

控制输出

以参数做为输出前缀:

parallel --tag echo foo-{} ::: a b c

输出:

a       foo-a
b       foo-b
c       foo-c

修改输出前缀 –tagstring:

parallel --tagstring {}-bar echo foo-{} ::: a b c

输出:

 a-bar       foo-a

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。