1. 為什么需要xargs命令
1.1 管道|的缺陷
管道實(shí)現(xiàn)的是將前面的輸出stdout
作為后面的輸入stdin
照皆,但是有些命令不接受管道的傳遞方式恨旱。例如:ls
模她,這是為什么呢?因?yàn)橛行┟钕M艿纻鬟f過(guò)來(lái)的是參數(shù),但是直接使用管道有時(shí)無(wú)法傳遞到命令的參數(shù)位乖篷。這時(shí)候就需要xargs
凉蜂,xargs
實(shí)現(xiàn)的是將管道傳遞過(guò)來(lái)的stdin
進(jìn)行處理然后傳遞到命令的參數(shù)位置上。
用戶查找文件:
用戶希望處理查找后的文件:
也就是xargs完成了兩個(gè)行為:
1. 處理管道傳輸過(guò)來(lái)的
stdin
羔杨;
2. 將處理后的數(shù)據(jù)傳遞到正確的位置捌臊;
1.2 xargs對(duì)數(shù)據(jù)的處理
處理大量數(shù)據(jù)的時(shí)候,可能會(huì)發(fā)生參數(shù)列表過(guò)長(zhǎng)的情況问畅。而xargs將完成參數(shù)的定位我們清楚娃属,但是
xrags
如何處理管道傳輸?shù)?strong>stdin
呢六荒?
其實(shí)就是完成兩個(gè)操作:
1. 對(duì)數(shù)據(jù)的分割;
2. 對(duì)數(shù)據(jù)的分批矾端;
xargs處理的優(yōu)先級(jí)或順序:先分割掏击,在分批,然后傳遞到參數(shù)位秩铆。
可以設(shè)想一個(gè)場(chǎng)景砚亭,我想對(duì)一堆數(shù)據(jù)進(jìn)行處理,實(shí)際上是對(duì)一堆中的每個(gè)數(shù)據(jù)進(jìn)行分別的處理殴玛。那么如何將一堆數(shù)據(jù)按照自定義規(guī)則分割為獨(dú)立的數(shù)據(jù)捅膘?若是一次性傳遞的數(shù)據(jù)過(guò)多,又該如何處理滚粟?
1.2.1 xrags的并發(fā)處理
但需要注意的是寻仗,盡管實(shí)現(xiàn)了分批處理,但是默認(rèn)情況下并沒(méi)有提高任何效率凡壤,因?yàn)榉峙鷤鬟f之后還是一次執(zhí)行一個(gè)署尤。而且有時(shí)候分批之后是將其作為一個(gè)參數(shù)的整體,并不會(huì)將分批中的信息分段執(zhí)行亚侠。
但事實(shí)上曹体,xargs
提高了-P
選項(xiàng),用于指定并發(fā)執(zhí)行的數(shù)量(默認(rèn)是只要一個(gè)處理進(jìn)程硝烂,不會(huì)提供效率箕别,但是可以指定為N個(gè)子進(jìn)程,或者指定為0表示盡可能多的利用CPU
)滞谢。這樣就能將讓分批操作更好的利用多核CPU串稀,從而提升效率。例如上面分成了兩批狮杨,指定-P 2
可以并發(fā)執(zhí)行兩批厨诸,而并非執(zhí)行完第一批之后再執(zhí)行第二批。
剩下的功能就是處理xargs
的細(xì)節(jié)問(wèn)題了禾酱,比如如何分割(xargs微酬、xargs -d、xargs -0)
颤陶,分割后如何劃批(xargs -n颗管、xargs -L)
,參數(shù)如何傳遞(xargs -i)
滓走。另外xargs
還提供了詢問(wèn)交互處理(-p
選項(xiàng))和預(yù)先打印一遍命令執(zhí)行情況(-t
選項(xiàng))垦江,傳遞終止符(-E
選項(xiàng))等。
1.2.2 執(zhí)行命令準(zhǔn)備
命令準(zhǔn)備:
[root@xuexi tmp]$ cd /tmp
[root@xuexi tmp]$ rm -fr *
[root@xuexi tmp]$ mkdir a b c d test logdir shdir
[root@xuexi tmp]$ touch "one space.log"
[root@xuexi tmp]$ touch logdir/{1..10}.log
[root@xuexi tmp]$ touch shdir/{1..5}.sh
[root@xuexi tmp]$ echo "the second sh the second line" > shdir/2.sh
[root@xuexi tmp]$ cat <<eof>shdir/1.sh
> the first sh
> the second line
> eof
1.2.3 Linux空格含義
那么按照什么規(guī)則進(jìn)行“分割”以及“分批”呢搅方?
Linux文件空格分類(lèi)(重點(diǎn)):
-
正方形(
\t
)代表:(標(biāo)記意義)制表符; - 圓形(空格)代表:(文本意義)普通空格衩藤;
-
長(zhǎng)方形(
\n
)代表:(標(biāo)記意義)換行符吧慢;
- 橢圓形代表:(文本意義)換行符;
- 長(zhǎng)方形代表:(標(biāo)記意義)換行符赏表;
2. xrags的分割行為
xargs
命令會(huì)將接收的stdin所有的空白(空格检诗、制表符、換行符)都轉(zhuǎn)換為空格瓢剿。我們使用xargs -d "xx"
自定義規(guī)則對(duì)數(shù)據(jù)進(jìn)行切分逢慌。默認(rèn)情況下,xargs使用空格來(lái)切分?jǐn)?shù)據(jù)间狂。
注意事項(xiàng)
- xargs -d可以指定分割符攻泼,可以是單個(gè)符號(hào)、字母或者數(shù)字鉴象。如指定
o
為分割符:xargs -d "o"
坠韩; - xargs -d是分割階段的選項(xiàng),所以會(huì)優(yōu)先于分批選項(xiàng)
(-n炼列、-L、-i)
- xargs -d不是先
xargs
在-d
處理的音比,它是區(qū)別于獨(dú)立的xargs
的另外一個(gè)分割選項(xiàng)俭尖。
1. xargs -d原理
替換:將接收stdin所有的【標(biāo)記意義】的符號(hào)替換為\n,替換完成后所有的符號(hào)(空格洞翩、制表符稽犁、分行符)變成【文本意義】上的普通符號(hào)。
分段:根據(jù)-d指定的分隔符進(jìn)行分段骚亿,并用空格分開(kāi)每段已亥,由于發(fā)生了【替換】操作,所以符號(hào)都是【文本意義】上的来屠。會(huì)導(dǎo)致分段中可能包含了空格虑椎、制表符、分行符俱笛。也就是說(shuō)處了-d導(dǎo)致的【分段空格】捆姜,其余所有符號(hào)都是分段中的一部分。
輸出:最后根據(jù)指定的【分批選項(xiàng)】來(lái)輸出迎膜。
2. 案例分析
默認(rèn)情況下泥技,使用空格進(jìn)行分割,但若是指定自定義分割符(此處使用o)磕仅,那么將o替換為分段空格后珊豹,切分獨(dú)立整體簸呈。
xargs -d "o"進(jìn)行自定義分割后,然后分批店茶,我們可以看到蜕便,實(shí)際上分成了2批。
3. xrags -0命令
xargs -0
的行為和xargs -d
基本一樣忽妒,只是-d
是指定分割符玩裙,-0
是指定固定的\0
作為分割符。等價(jià)于xargs -d "\0"
段直。
(注意)xargs -0
可以處理接收到的stdin
中的null字符(\0)
吃溅。如果不使用-0
選項(xiàng)或-null
選項(xiàng),檢測(cè)到\0
后會(huì)給出警告提醒鸯檬,并只向命令傳遞非\0
段决侈。
【tr
命令:替換或者刪除字符】
4. 實(shí)際應(yīng)用:
-xargs -0的包含空格的文件的操作。
【起因】使用find+rm命令無(wú)法刪除帶有空格的文件喧务。
【原因】:xargs默認(rèn)是以空白字符(空格赖歌、換行符、制表符)來(lái)分割記錄的功茴,實(shí)際上rm
刪除的數(shù)據(jù)便是./one
和file.txt
庐冯。而
【解決方案】:此時(shí)我們不能使用默認(rèn)的分割符,而應(yīng)該使用自定義的分割符坎穿!我們知道find
命令展父,文件后面均是換行符。
【解決方案】為了解決這個(gè)問(wèn)題玲昧,可以在每個(gè)文件將換行符替換為NULL(\0
)栖茉。這樣我們以\0
分割,就可以得到完整文件孵延。
為什么要使用\0
作為分割符吕漂,而不是其他字符呢?因?yàn)樵诰幊陶Z(yǔ)言中尘应,一般使用\0
作為結(jié)束標(biāo)志惶凝。而文件的路徑名不可能包含\0
。
本質(zhì)上是借助xargs的對(duì)\0的分割操作犬钢。find命令將換行符替換成\0梨睁。
3. xargs的分批行為
對(duì)于xargs,不寫(xiě)命令時(shí)默認(rèn)的執(zhí)行是
echo
娜饵。
將換行處理掉不是echo
實(shí)現(xiàn)的坡贺,而是管道傳遞過(guò)來(lái)的stdin經(jīng)過(guò)xargs處理后得到的。將所有【文本/標(biāo)記意義】空格、制表符和分行符都替換為【文本意義】上空格并壓縮到一行顯示遍坟。
【注意】這一整行將作為一個(gè)整體拳亿。這個(gè)整體可能直接交給命令或者作為stdout
通過(guò)管道傳遞給管道右邊的命令,這時(shí)結(jié)果將作為一個(gè)整體傳遞愿伴,也有可能被xargs
同時(shí)指定的【分批選項(xiàng)】分批處理肺魁。(這也是可能出現(xiàn)參數(shù)列表過(guò)長(zhǎng)的原因)
xargs分批命令總結(jié):
xargs -n :和獨(dú)立的xargs命令配合使用時(shí),按照默認(rèn)分割符(空格)進(jìn)行分批隔节,但配合x(chóng)args -d命令鹅经,則按自定義分割符分批。
xargs -L
和-n
選項(xiàng)類(lèi)似,唯一的區(qū)別就是-L
永遠(yuǎn)是按段劃批,而-n
和獨(dú)立的xargs
一起使用時(shí)是按空格分段劃批的丧裁。
2. 對(duì)獨(dú)立的xargs
指定分批選項(xiàng)
【標(biāo)記/文本】指定
-n
時(shí)按空格分段壶栋,然后劃批埠啃,不管是文本意義空格還是標(biāo)記意義的空格,只要是空格都是-n
的操作對(duì)象。【標(biāo)記】指定
-L
或者-i
時(shí)按段劃批,文本意義的符號(hào)不被處理强胰。
【需要注意的是】:【xargs -n】本質(zhì)上分為兩種情況:
- 和獨(dú)立的
xargs
一起使用,這時(shí)按照每個(gè)空格分段劃批妹沙;- 和
xargs -d
或xargs -0
一起使用偶洋,這時(shí)按段分批;xargs -L
和-n
選項(xiàng)類(lèi)似距糖,唯一的區(qū)別就是-L
永遠(yuǎn)是按段劃批玄窝,而-n
和獨(dú)立的xargs
一起使用時(shí)是按空格分段劃批的。
4 xargs -i 接收傳遞的分批結(jié)果
xargs -i
選項(xiàng)在邏輯上用于接收傳遞的分批結(jié)果肾筐。
如果不使用
-i
,則默認(rèn)是將分割處理
后的結(jié)果整體傳遞到【命令的最尾部】缸剪。但是有時(shí)候需要傳遞到多個(gè)位置吗铐,不使用-i
就不知道傳遞到哪個(gè)位置了。
例如:重命名備份的時(shí)候在每個(gè)傳遞過(guò)來(lái)的文件名加上后綴.bak
杏节,這需要兩個(gè)參數(shù)位唬渗。
語(yǔ)法:
使用xargs -i
時(shí)以大括號(hào){}
作為替換符號(hào),傳遞的時(shí)候看到{}
就將結(jié)果替換奋渔,可以將{}
放在任意需要傳遞的參數(shù)位置上镊逝。如果多個(gè)地方使用{}
就實(shí)現(xiàn)了多個(gè)傳遞。
xargs -I
和xargs -i
是一樣的嫉鲸,只是-i
默認(rèn)使用大括號(hào)作為替換符號(hào)撑蒜,-I
可以指定其他符號(hào)、字母、數(shù)字作為替換符號(hào)座菠,但是必須用引號(hào)
包起來(lái)狸眼。man推薦使用-I
代替-i
,但是一般使用-i
方便浴滴,除非在命令中不能使用{}
拓萌,例如touch {1...10}.log
時(shí),大括號(hào)就不能用來(lái)做替換符號(hào)升略。
分析:重命名備份的時(shí)候在每個(gè)傳遞過(guò)來(lái)的文件名加上后綴
.bak
微王。
案例分析1:
【./
指的是當(dāng)前目錄】
- 重命名邏輯是:
mv ./logdir/a.log ./logdir/a.log.bak
- 我們想將一個(gè)目錄下的文件都要執(zhí)行某些邏輯。
命令:ls logdir/ | xargs -i mv ./logdir/{} ./logdir/{}.bak
為什么將“-i”
選項(xiàng)劃分在分批選項(xiàng)里面品嚣,因?yàn)樗J(rèn)一個(gè)段就是一個(gè)批炕倘,每次傳遞一個(gè)批就是傳遞一個(gè)段到指定大括號(hào){}位上。不理解腰根,可以看下1.2.4 分批選項(xiàng)的生效規(guī)則
案例分析2:
例如:想將數(shù)字1-10
沒(méi)三個(gè)數(shù)顯示在start
和end
之間激才。
start 1 2 3 end
start 4 5 6 end
start 7 8 9 end
start 10 end
由于指定了參數(shù)傳遞位置,所以必須使用-i
额嘿,那就無(wú)法一次傳遞3個(gè)數(shù)瘸恼,要解決這個(gè)問(wèn)題,就要想辦法讓每三個(gè)樹(shù)分一次段册养,然后后使用-i
傳遞东帅,那么可以將每三個(gè)數(shù)分一次行寫(xiě)入一個(gè)文件。
例如:
當(dāng)然球拦,也可以多次使用xargs
靠闭。在很多使用無(wú)法解決分段的問(wèn)題都可以通過(guò)多次使用xargs
來(lái)解決。
5. 分批選項(xiàng)的生效規(guī)則
-i坎炼、-L愧膀、-n
選項(xiàng)都是分批選項(xiàng),他們的生效規(guī)則是:誰(shuí)指定在后面谣光,誰(shuí)就生效i萘堋!萄金!
實(shí)際上,-i
就是隱含了-L 1
氧敢,-i
是分批并傳遞這兩個(gè)作用跟嚴(yán)格些日戈。
6. xargs觀察命令的執(zhí)行過(guò)程
使用-p
選項(xiàng)是交互詢問(wèn)式的,只有每次詢問(wèn)的時(shí)候輸入y(或者yes)
才會(huì)執(zhí)行孙乖,直接按entry
鍵是不會(huì)執(zhí)行的浙炼。
使用-t
選項(xiàng)是在每次執(zhí)行xargs
后面的命令都會(huì)先在stderr
上打印一遍命令的執(zhí)行過(guò)程然后才正式執(zhí)行份氧。
使用-p
和-t
選項(xiàng)就可以根據(jù)xargs
后面的命令的執(zhí)行順序進(jìn)行推測(cè),xargs
是如何分段鼓拧,分批以及傳遞的半火。
【后續(xù)】 分批選項(xiàng)的的典型應(yīng)用
1. 同一目錄下文件過(guò)多
分批選項(xiàng)有時(shí)特別有用,例如腳本規(guī)定每次只能傳遞三個(gè)參數(shù)季俩,有時(shí)候grep
或者rm -rf
文件數(shù)量特別多的時(shí)候會(huì)提示參數(shù)列表過(guò)長(zhǎng)
而導(dǎo)致失敗钮糖,這時(shí)候就可以分批來(lái)按批查詢或刪除。
命令:ls | xargs -n 10000 rm -rf
2. xargs+find的使用
xargs原本就是為find而開(kāi)發(fā)的酌住。
find命令將匹配到的文件傳遞給xargs
命令店归,而xargs
命令每次只獲取一部分而不是全部。不像-exec
選項(xiàng)那樣酪我,這樣就可以先處理最先獲取的一部分文件消痛,然后是下一批。
實(shí)際應(yīng)用:
ls+grep
跨目錄查詢時(shí)都哭,我們將文件通過(guò)管道輸入到grep
參數(shù)處秩伞,此時(shí)并沒(méi)有包含目錄地址,邊會(huì)出現(xiàn)下面的錯(cuò)誤欺矫。
解決方案:
將find
找到的文件地址傳遞給grep
命令的參數(shù)處纱新。