GNU Parallel
来源:互联网 发布:普通java项目编译运行 编辑:程序博客网 时间:2024/06/06 05:34
GNU Parallel
它是什么?
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
安装最新版:
1
(wget -O - pi.dk/3 || curl pi.dk/3/) |
bash
这条命令同时也会安装最新版的指南
1
man
parallel_tutorial
本教程的大部分内容同时也兼容旧版本。
abc-file
生成文件:
1
parallel -k
echo
::: A B C > abc-
file
def-file
生成文件:
1
parallel -k
echo
::: D E F > def-
file
abc0-file
生成文件:
1
perl -e
'printf "A\0B\0C\0"'
> abc0-
file
abc_-file
生成文件:
1
perl -e
'printf "A_B_C_"'
> abc_-
file
tsv_file.tsv
生成文件:
1
perl -e
'printf "f1\tf2\nA\tB\nC\tD\n"'
> tsv-
file
.tsv
num30000
生成文件:
1
perl -e
'for(1..30000){print "$_\n"}'
> num30000
num1000000
生成文件:
1
perl -e
'for(1..1000000){print "$_\n"}'
> num1000000
num_%header
生成文件:
1
(
echo
%head1;
echo
%head2; perl -e
'for(1..10){print "$_\n"}'
) > num_%header
远程执行:ssh免密码登录$SERVER1和$SERVER2
生成文件:
1
SERVER1=server.example.com
2
SERVER2=server2.example.net
最后应该成功运行如下命令:
1
ssh
$SERVER1
echo
works
2
ssh
$SERVER2
echo
works
使用 ssh-keygen -t dsa; ssh-copy-id $SERVER1 建立环境(使用empty pass phrase)
输入源
GNU Parallel的输入源支持文件、命令行和标准输入(stdin或pipe)
单个输入源
从命令行读取输入:
1
parallel
echo
::: A B C
输出(由于任务以并行的方式执行,顺序可能会有所不同):
1
A
2
B
3
C
文件做为输入源:
1
parallel -a abc-
file
echo
输出同上。
STDIN(标准输入)做为输入源:
1
cat
abc-
file
| parallel
echo
输出同上。
多输入源
GNU Parallel支持通过命令行指定多个输入源,它会生成所有的组合:
1
parallel
echo
::: A B C ::: D E F
输出:
1
A D
2
A E
3
A F
4
B D
5
B E
6
B F
7
C D
8
C E
9
C F
多个文件做为输入源:
1
parallel -a abc-
file
-a def-
file
echo
输出同上。
STDIN(标准输入)可以做为输入源中的一个,使用“-”:
1
cat
abc-
file
| parallel -a - -a def-
file
echo
输出同上。
可以使用“::::”替代 -a:
1
cat
abc-
file
| parallel
echo
:::: - def-
file
输出同上。
::: 和 :::: 可以混合使用:
1
parallel
echo
::: A B C :::: def-
file
输出同上。
适配参数
–xapply 从每一个输入源取一个参数:
1
parallel --xapply
echo
::: A B C ::: D E F
输出:
1
A D
2
B E
3
C F
如果其中一个输入源的长度比较短,它的值会被重复:
1
parallel --xapply
echo
::: A B C D E ::: F G
输出:
1
A F
2
B G
3
C F
4
D G
5
E F
改变参数分隔符
GNU Parallel可以指定分隔符替代 ::: 或 ::::,当这两个符号被其它命令占用的时候会特别有用:
1
parallel --arg-sep ,,
echo
,, A B C :::: def-
file
输出:
1
A D
2
A E
3
A F
4
B D
5
B E
6
B F
7
C D
8
C E
9
C F
改变参数分隔符:
1
parallel --arg-
file
-sep //
echo
::: A B C // def-
file
输出同上。
改变参数定界符
GNU Parallel默认把一行做为一个参数:使用 \n 做为参数定界符。可以使用 -d 改变:
1
parallel -d _
echo
:::: abc_-
file
输出:
1
A
2
B
3
C
\0 代表NULL:
1
parallel -d
'\0'
echo
:::: abc0-
file
输出同上。
-0 是 -d '\0' 的简写(通常用于从 find … -print0读取输入):
1
parallel -0
echo
:::: abc0-
file
输出同上。
输入源中的结束值
GNU Parallel支持指定一个值做为结束标志:
1
parallel -E stop
echo
::: A B stop C D
输出:
1
A
2
B
跳过空行
使用 –no-run-if-empty 来跳过空行:
1
(
echo
1;
echo
;
echo
2) | parallel --no-run-
if
-empty
echo
输出:
1
1
2
2
构建命令行
没有指定命令意味着参数就是命令
如果parallel之后没有给定命令,那么这些参数会被当做命令:
1
parallel :::
ls
'echo foo'
pwd
输出:
1
[当前文件列表]
2
foo
3
[当前工作目录的路径]
命令可以是一个脚本文件,一个二进制可执行文件或一个bash的函数(须用 export -f 导出函数):
1
# Only works in Bash and only if $SHELL=.../bash
2
my_func() {
3
echo
in
my_func $1
4
}
5
export
-f my_func
6
parallel my_func ::: 1 2 3
输出:
1
in
my_func 1
2
in
my_func 2
3
in
my_func 3
替换字符串
5种替换字符串
GNU Parallel支持多种替换字符串。默认使用 {}:
1
parallel
echo
::: A/B.C
输出:
1
A/B.C
指定 {} :
1
parallel
echo
{} ::: A/B.C
输出同上
去掉扩展名 {.}:
1
parallel
echo
{.} ::: A/B.C
输出
1
A/B
去掉路径 {/}:
1
parallel
echo
{/} ::: A/B.C
输出:
1
B.C
只保留路径 {//}:
1
parallel
echo
{//} ::: A/B.C
输出:
1
A
去掉路径和扩展名 {/.}:
1
parallel
echo
{/.} ::: A/B.C
输出:
1
B
输出任务编号:
1
parallel
echo
{
#} ::: A/B.C
输出:
1
1
2
2
3
3
改变替换字符串
使用 -I 改变替换字符串符号 {}:
1
parallel -I ,,
echo
,, ::: A/B.C
输出:
1
A/B.C
–extensionreplace替换 {.}:
1
parallel --extensionreplace ,,
echo
,, ::: A/B.C
输出:
1
A/B
–basenamereplace替换 {/}:
1
parallel --basenamereplace ,,
echo
,, ::: A/B.C
输出:
1
B.C
–dirnamereplace替换 {//}:
1
parallel --dirnamereplace ,,
echo
,, ::: A/B.C
输出:
1
A
–basenameextensionreplace替换 {/.}:
1
parallel --basenameextensionreplace ,,
echo
,, ::: A/B.C
输出:
1
B
–seqreplace替换 {#}:
1
parallel --seqreplace ,,
echo
,, ::: A B C
输出:
1
1
2
2
3
3
指定位置替换字符串
如果有多个输入源时,可以通过 {编号} 指定某一个输入源的参数:
1
parallel
echo
{1} and {2} ::: A B ::: C D
输出:
1
A and C
2
A and D
3
B and C
4
B and D
可以使用 / // /. 和 .: 改变指定替换字符串:
1
parallel
echo
/={1/} //={1//} /.={1/.} .={1.} ::: A/B.C D/E.F
输出:
1
/=B.C //=A /.=B .=A/B
2
/=E.F //=D /.=E .=D/E
位置可以是负数,表示倒着数:
1
parallel
echo
1={1} 2={2} 3={3} -1={-1} -2={-2} -3={-3} ::: A B ::: C D ::: E F
输出:
1
1=A 2=C 3=E -1=E -2=C -3=A
2
1=A 2=C 3=F -1=F -2=C -3=A
3
1=A 2=D 3=E -1=E -2=D -3=A
4
1=A 2=D 3=F -1=F -2=D -3=A
5
1=B 2=C 3=E -1=E -2=C -3=B
6
1=B 2=C 3=F -1=F -2=C -3=B
7
1=B 2=D 3=E -1=E -2=D -3=B
8
1=B 2=D 3=F -1=F -2=D -3=B
按列输入
使用 –colsep 把文件中的行切分为列,做为输入参数。下面使用TAB(\t):
1
1=f1 2=f2
2
1=A 2=B
3
1=C 2=D
指定参数名
使用 –header 把每一行输入中的第一个值做为参数名:
1
parallel --header :
echo
f1={f1} f2={f2} ::: f1 A B ::: f2 C D
输出:
1
f1=A f2=C
2
f1=A f2=D
3
f1=B f2=C
4
f1=B f2=D
使用 –colsep 处理使用TAB做为分隔符的文件:
1
parallel --header : --colsep
'\t'
echo
f1={f1} f2={f2} :::: tsv-
file
.tsv
输出:
1
f1=A f2=B
2
f1=C f2=D
多参数
–xargs 让GNU Parallel支持一行多个参数(可以指定上限):
1
cat
num30000 | parallel --
xargs
echo
|
wc
-l
输出:
1
2
30000个参数被分为两行。
一行中的参数个数的上限通过 -s 指定。下面指定最大长度是10000,会被分为17行:
1
cat
num30000 | parallel --
xargs
-s 10000
echo
|
wc
-l
输出:
1
为了获得更好的并发性,GNU Parallel会在文件读取结束后再分发参数。
GNU Parallel 在读取完最后一个参数之后,才开始第二个任务,此时会把所有的参数平均分配到4个任务(如果指定了4个任务)。
第一个任务与上面使用 –xargs 的例子一样,但是第二个任务会被平均的分成4个任务,最终一共5个任务。
1
cat
num30000 | parallel --jobs 4 -m
echo
|
wc
-l
输出:
1
5
10分参数分配到4个任务可以看得更清晰:
1
parallel --jobs 4 -m
echo
::: {1..10}
输出:
1
1 2 3
2
4 5 6
3
7 8 9
4
10
替换字符串可以是单词的一部分。通过下面两个命令体会 -m 和 -X 的区别:
1
parallel --jobs 4 -m
echo
pre-{}-post ::: A B C D E F G
输出:
1
pre-A B-post
2
pre-C D-post
3
pre-E F-post
4
pre-G-post
-X与 -m 相反:
1
parallel --jobs 4 -X
echo
pre-{}-post ::: A B C D E F G
输出:
1
pre-A-post pre-B-post
2
pre-C-post pre-D-post
3
pre-E-post pre-F-post
4
pre-G-post
使用 -N 限制每行参数的个数:
1
parallel -N3
echo
::: A B C D E F G H
输出:
1
A B C
2
D E F
3
G H
-N也可以用于指定位置替换字符串:
1
parallel -N3
echo
1={1} 2={2} 3={3} ::: A B C D E F G H
输出:
1
1=A 2=B 3=C
2
1=D 2=E 3=F
3
1=G 2=H 3=
-N0 只读取一个参数,但不附加:
1
parallel -N0
echo
foo ::: 1 2 3
输出:
1
foo
2
foo
3
foo
引用
如果命令行中包含特殊字符,就需要使用引号保护起来。
perl脚本 'print “@ARGV\n”' 与linux的 echo 的功能一样。
1
perl -e
'print "@ARGV\n"'
A
输出:
1
A
使用GNU Parallel运行这条命令的时候,perl命令需要用引号包起来:
1
parallel perl -e
'print "@ARGV\n"'
::: This wont work
输出:
1
[Nothing]
使用 -q 保护perl命令:
1
parallel -q perl -e
'print "@ARGV\n"'
::: This works
输出:
1
This
2
works
也可以使用 ' :
1
parallel perl -e \
''
print
"@ARGV\n"
'\' ::: This works, too
输出:
1
This
2
works,
3
too
使用 -quote:
1
parallel --shellquote
2
parallel: Warning: Input is
read
from the terminal. Only experts
do
this on purpose. Press CTRL-D to
exit
.
3
perl -e
'print "@ARGV\n"'
4
[CTRL-D]
输出:
1
perl\ -e\ \'print\ \"@ARGV\\n\"\'
也可以使用命令:
1
parallel perl\ -e\ \'print\ \"@ARGV\\n\"\' ::: This also works
输出:
1
This
2
also
3
works
去除空格
使用 –trim 去除参数两头的空格:
1
parallel --trim r
echo
pre-{}-post :::
' A '
输出:
1
pre- A-post
删除左边的空格:
1
parallel --trim l
echo
pre-{}-post :::
' A '
输出:
1
pre-A -post
删除两边的空格:
1
parallel --trim lr
echo
pre-{}-post :::
' A '
输出:
1
pre-A-post
控制输出
以参数做为输出前缀:
1
parallel --tag
echo
foo-{} ::: A B C
输出:
1
A foo-A
2
B foo-B
3
C foo-C
修改输出前缀 –tagstring:
1
parallel --tagstring {}-bar
echo
foo-{} ::: A B C
输出:
1
A-bar foo-A
2
B-bar foo-B
3
C-bar foo-C
查看有哪些命令会被执行:
1
parallel --dryrun
echo
{} ::: A B C
输出:
1
echo
A
2
echo
B
3
echo
C
运行之前先打印命令 –verbose:
1
parallel --verbose
echo
{} ::: A B C
输出:
1
echo
A
2
echo
B
3
A
4
echo
C
5
B
6
C
GNU Parallel 会延迟输出,直到命令执行完成:
1
parallel -j2
'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end'
::: 4 2 1
输出:
1
2-start
2
2-middle
3
2-end
4
1-start
5
1-middle
6
1-end
7
4-start
8
4-middle
9
4-end
立即打印输出 –ungroup:
1
parallel -j2 --ungroup
'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end'
::: 4 2 1
输出:
1
4-start
2
42-start
3
2-middle
4
2-end
5
1-start
6
1-middle
7
1-end
8
-middle
9
4-end
使用 –ungroup 会很快,但会导致输出错乱,一个任务的行输出可能会被另一个任务的输出截断。像上例所示,第二行输出混合了两个任务: '4-middle' '2-start'
使用 –linebuffer避免这个问题(稍慢一点):
1
parallel -j2 --linebuffer
'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end'
::: 4 2 1
输出:
1
4-start
2
2-start
3
2-middle
4
2-end
5
1-start
6
1-middle
7
1-end
8
4-middle
9
4-end
强制使输出与参数保持顺序 –keep-order/-k:
1
parallel -j2 -k
'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end'
::: 4 2 1
输出:
1
4-start
2
4-middle
3
4-end
4
2-start
5
2-middle
6
2-end
7
1-start
8
1-middle
9
1-end
把输出保存到文件中
GNU Parallel可以把每一个任务的输出保存到文件中:
1
parallel --files ::: A B C
输出与下面类似:
1
/tmp/pAh6uWuQCg.par
2
/tmp/opjhZCzAX4.par
3
/tmp/W0AT_Rph2o.par
临时文件默认保存在 /tmp 中,可以使用 –tmpdir改变(或者修改 $TMPDIR):
1
parallel --tmpdir /var/tmp --files ::: A B C
输出:
1
/var/tmp/pAh6uWuQCg.par
2
/var/tmp/opjhZCzAX4.par
3
/var/tmp/W0AT_Rph2o.par
或者修改 $TMPDIR :
1
TMPDIR=/var/tmp parallel --files ::: A B C
输出同上。
输出文件可以有结构的保存 –results:
1
parallel --results outdir
echo
::: A B C
输出:
1
A
2
B
3
C
输出文件不仅包含标准输出(stdout)也会包含标准错误输出(stderr):
1
outdir/1/A/stderr
2
outdir/1/A/stdout
3
outdir/1/B/stderr
4
outdir/1/B/stdout
5
outdir/1/C/stderr
6
outdir/1/C/stdout
在使用多个变量的时候会显示很有用:
1
parallel --header : --results outdir
echo
::: f1 A B ::: f2 C D
生成的文件:
1
outdir/f1/A/f2/C/stderr
2
outdir/f1/A/f2/C/stdout
3
outdir/f1/A/f2/D/stderr
4
outdir/f1/A/f2/D/stdout
5
outdir/f1/B/f2/C/stderr
6
outdir/f1/B/f2/C/stdout
7
outdir/f1/B/f2/D/stderr
8
outdir/f1/B/f2/D/stdout
控制执行
并行任务数
使用 –jobs/-j 指定并行任务数:
1
/usr/bin/
time
parallel -N0 -j64
sleep
1 ::: {1..128}
使用64个任务执行128个休眠命令,大概耗时2到8秒。
默认情况下并行任务数与cpu核心数相同,所以这条命令:
1
/usr/bin/
time
parallel -N0
sleep
1 ::: {1..128}
会比每个cpu两个任务的耗时多一倍:
1
/usr/bin/
time
parallel -N0 --jobs 200%
sleep
1 ::: {1..128}
使用 –jobs 0 表示执行尽可能多的并行任务:
1
/usr/bin/
time
parallel -N0 --jobs 0
sleep
1 ::: {1..128}
通常耗时1到7秒。
可以从文件中读取并行任务数,这样的话,每个任务完成的时候都会重新读取一次文件:
1
echo
50% > my_jobs
2
/usr/bin/
time
parallel -N0 --jobs my_jobs
sleep
1 ::: {1..128} &
3
sleep
1
4
echo
0 > my_jobs
5
wait
前两个任务都是只用了一半的cpu,当文件内容变成0之后,后面的任务就会尽可能多的并行执行。
除了基于cpu使用率之外,也可以基于cpu数:
1
parallel --use-cpus-instead-of-cores -N0
sleep
1 ::: {1..128}
交互
通过使用 –interactive 在一个任务执行之前让用户决定是否执行:
1
parallel --interactive
echo
::: 1 2 3
输出:
1
echo
1 ?...y
2
echo
2 ?...n
3
1
4
echo
3 ?...y
5
3
未完,待续
- GNU Parallel
- GNU Parallel in caffe
- GNU Parallel神器入门
- GNU Parallel: 并行执行Linux命令
- Blat_类BLAST 比对工具 & GNU Parallel
- GNU Parallel -- "shell for" not fashion, 用Parallel瞬间将场面hold住
- Parallel
- 如何利用GNU Parallel工具在单机上处理百万级数量规模的文件
- GNU
- GNU
- GNU
- GNU
- GNU
- GNU
- GNU
- GNU
- GNU
- GNU
- shell 字符串处理
- hdu 1181 变形课
- 母函数系列之找单词 hdoj 2082
- mac 同时安装多个版本的JDK
- java 获取控制台的输入的两个方法
- GNU Parallel
- a new Webcam Api Tutorial in C++ for Windows(Windows Media Foundation)--WMF
- 多线程例子
- UGC(互联网术语)
- 回归:java基本术语
- 范德萨范德萨发的范德萨范德萨范德萨范德萨
- Maven多环境配置实战 filter
- The new begining
- 终于搞定了一个小软件