它是什么?
GNU Parallel是一個(gè)shell工具,為了在一臺(tái)或多臺(tái)計(jì)算機(jī)上并行的執(zhí)行計(jì)算任務(wù),一個(gè)計(jì)算任務(wù)可以是一條shell命令或者一個(gè)以每一行做為輸入的腳本程序。通常的輸入是文件列表、主機(jī)列表、用戶列表、URL列表或者表格列表;一個(gè)計(jì)算任務(wù)也可以是一個(gè)從管道讀取的一條命令。GNU Parallel會(huì)把輸入分塊,然后通過(guò)管道并行的執(zhí)行。
如果你會(huì)使用xargs和tee命令,你會(huì)發(fā)現(xiàn)GNU Parallel非常易于使用,因?yàn)镚NU Parallel具有與xargs一樣的選項(xiàng)。GNU Parallel可以替代大部分的shell循環(huán),并且用并行的方式更快的完成計(jì)算任務(wù)。
GNU Parallel保證它的輸出與順序執(zhí)行計(jì)算任務(wù)時(shí)是一樣的,這樣就可以方便的把GNU Parallel的輸出做為其它程序的輸入。
對(duì)于每一行輸入,GNU Parallel會(huì)把這一行做為參數(shù)來(lái)運(yùn)行指定的命令。如果沒(méi)有給出命令,那么這一行會(huì)被當(dāng)做命令執(zhí)行。多行輸入會(huì)并行的運(yùn)行。GNU Parallel經(jīng)常被用于替代xargs或者cat | bash。
指南
本教程展示了絕大多數(shù)GNU Parallel的功能。旨在介紹GNU Parallel中的一個(gè)選項(xiàng),而非講解真實(shí)世界中使用的例子?;ㄒ粋€(gè)小時(shí)的時(shí)間學(xué)習(xí)本教程,你會(huì)由此愛(ài)上上命令行。
預(yù)備
為了執(zhí)行本教程中的示例,你首先需要做如下準(zhǔn)備:
parallel >= version 20130814
安裝最新版:
(wget -O - pi.dk/3 || curl pi.dk/3/) | bash
這條命令同時(shí)也會(huì)安裝最新版的指南
本教程的大部分內(nèi)容同時(shí)也兼容舊版本。
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
遠(yuǎn)程執(zhí)行:ssh免密碼登錄$SERVER1和$SERVER2
生成文件:
SERVER1=server.example.com
SERVER2=server2.example.net
最后應(yīng)該成功運(yùn)行如下命令:
ssh $SERVER1 echo works
ssh $SERVER2 echo works
使用 ssh-keygen -t dsa; ssh-copy-id $SERVER1 建立環(huán)境(使用empty pass phrase)
輸入源
GNU Parallel的輸入源支持文件、命令行和標(biāo)準(zhǔn)輸入(stdin或pipe)
單個(gè)輸入源
從命令行讀取輸入:
輸出(由于任務(wù)以并行的方式執(zhí)行,順序可能會(huì)有所不同):
A
B
C
文件做為輸入源:
parallel -a abc-file echo
輸出同上。
STDIN(標(biāo)準(zhǔn)輸入)做為輸入源:
cat abc-file | parallel echo
輸出同上。
多輸入源
GNU Parallel支持通過(guò)命令行指定多個(gè)輸入源,它會(huì)生成所有的組合:
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
多個(gè)文件做為輸入源:
parallel -a abc-file -a def-file echo
輸出同上。
STDIN(標(biāo)準(zhǔn)輸入)可以做為輸入源中的一個(gè),使用“-”:
cat abc-file | parallel -a - -a def-file echo
輸出同上。
可以使用“::::”替代 -a:
cat abc-file | parallel echo :::: - def-file
輸出同上。
::: 和 :::: 可以混合使用:
parallel echo ::: A B C :::: def-file
輸出同上。
適配參數(shù)
–xapply 從每一個(gè)輸入源取一個(gè)參數(shù):
parallel --xapply echo ::: A B C ::: D E F
輸出:
A D
B E
C F
如果其中一個(gè)輸入源的長(zhǎng)度比較短,它的值會(huì)被重復(fù):
parallel --xapply echo ::: A B C D E ::: F G
輸出:
A F
B G
C F
D G
E F
改變參數(shù)分隔符
GNU Parallel可以指定分隔符替代 ::: 或 ::::,當(dāng)這兩個(gè)符號(hào)被其它命令占用的時(shí)候會(huì)特別有用:
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
改變參數(shù)分隔符:
parallel --arg-file-sep // echo ::: A B C // def-file
輸出同上。
改變參數(shù)定界符
GNU Parallel默認(rèn)把一行做為一個(gè)參數(shù):使用 \n 做為參數(shù)定界符。可以使用 -d 改變:
parallel -d _ echo :::: abc_-file
輸出:
A
B
C
\0 代表NULL:
parallel -d '\0' echo :::: abc0-file
輸出同上。
-0 是 -d '\0' 的簡(jiǎn)寫(通常用于從 find … -print0讀取輸入):
parallel -0 echo :::: abc0-file
輸出同上。
輸入源中的結(jié)束值
GNU Parallel支持指定一個(gè)值做為結(jié)束標(biāo)志:
parallel -E stop echo ::: A B stop C D
輸出:
A
B
跳過(guò)空行
使用 –no-run-if-empty 來(lái)跳過(guò)空行:
(echo 1; echo; echo 2) | parallel --no-run-if-empty echo
輸出:
1
2
構(gòu)建命令行
沒(méi)有指定命令意味著參數(shù)就是命令
如果parallel之后沒(méi)有給定命令,那么這些參數(shù)會(huì)被當(dāng)做命令:
parallel ::: ls 'echo foo' pwd
輸出:
[當(dāng)前文件列表]
foo
[當(dāng)前工作目錄的路徑]
命令可以是一個(gè)腳本文件,一個(gè)二進(jìn)制可執(zhí)行文件或一個(gè)bash的函數(shù)(須用 export -f 導(dǎo)出函數(shù)):
# 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支持多種替換字符串。默認(rèn)使用 {}:
輸出:
A/B.C
指定 {} :
parallel echo {} ::: A/B.C
輸出同上
去掉擴(kuò)展名 {.}:
parallel echo {.} ::: A/B.C
輸出
A/B
去掉路徑 {/}:
parallel echo {/} ::: A/B.C
輸出:
B.C
只保留路徑 {//}:
parallel echo {//} ::: A/B.C
輸出:
A
去掉路徑和擴(kuò)展名 {/.}:
parallel echo {/.} ::: A/B.C
輸出:
B
輸出任務(wù)編號(hào):
parallel echo {#} ::: A/B.C
輸出:
1
2
3
改變替換字符串
使用 -I 改變替換字符串符號(hào) {}:
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
指定位置替換字符串
如果有多個(gè)輸入源時(shí),可以通過(guò) {編號(hào)} 指定某一個(gè)輸入源的參數(shù):
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
位置可以是負(fù)數(shù),表示倒著數(shù):
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 把文件中的行切分為列,做為輸入?yún)?shù)。下面使用TAB(\t):
1=f1 2=f2
1=A 2=B
1=C 2=D
指定參數(shù)名
使用 –header 把每一行輸入中的第一個(gè)值做為參數(shù)名:
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
多參數(shù)
–xargs 讓GNU Parallel支持一行多個(gè)參數(shù)(可以指定上限):
cat num30000 | parallel --xargs echo | wc -l
輸出:
2
30000個(gè)參數(shù)被分為兩行。
一行中的參數(shù)個(gè)數(shù)的上限通過(guò) -s 指定。下面指定最大長(zhǎng)度是10000,會(huì)被分為17行:
cat num30000 | parallel --xargs -s 10000 echo | wc -l
為了獲得更好的并發(fā)性,GNU Parallel會(huì)在文件讀取結(jié)束后再分發(fā)參數(shù)。
GNU Parallel 在讀取完最后一個(gè)參數(shù)之后,才開始第二個(gè)任務(wù),此時(shí)會(huì)把所有的參數(shù)平均分配到4個(gè)任務(wù)(如果指定了4個(gè)任務(wù))。
第一個(gè)任務(wù)與上面使用 –xargs 的例子一樣,但是第二個(gè)任務(wù)會(huì)被平均的分成4個(gè)任務(wù),最終一共5個(gè)任務(wù)。
cat num30000 | parallel --jobs 4 -m echo | wc -l
輸出:
5
10分參數(shù)分配到4個(gè)任務(wù)可以看得更清晰:
parallel --jobs 4 -m echo ::: {1..10}
輸出:
1 2 3
4 5 6
7 8 9
10
替換字符串可以是單詞的一部分。通過(guò)下面兩個(gè)命令體會(huì) -m 和 -X 的區(qū)別:
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 限制每行參數(shù)的個(gè)數(shù):
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 只讀取一個(gè)參數(shù),但不附加:
parallel -N0 echo foo ::: 1 2 3
輸出:
foo
foo
foo
引用
如果命令行中包含特殊字符,就需要使用引號(hào)保護(hù)起來(lái)。
perl腳本 'print “@ARGV\n”' 與linux的 echo 的功能一樣。
perl -e 'print "@ARGV\n"' A
輸出:
A
使用GNU Parallel運(yùn)行這條命令的時(shí)候,perl命令需要用引號(hào)包起來(lái):
parallel perl -e 'print "@ARGV\n"' ::: This wont work
輸出:
[Nothing]
使用 -q 保護(hù)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 去除參數(shù)兩頭的空格:
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
控制輸出
以參數(shù)做為輸出前綴:
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
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。