Xargs的使用ide
發現xargs是個很好用的命令,因而搜索了網上好多關於xargs的文章並作了相關的實驗,現本身總結一下,好轉化爲本身的東西:this
Xargs常常會與管道搞混淆,因此spa
首先咱們先了解下管道的做用:命令行
管道實現的是:將前面的stdout做爲後面的stdin進行傳遞。但有些命令是不接受管道的傳遞方式,好比:ls (#echo ‘/root’| ls )設計
‚ 管道傳遞過來的stdin只能做爲內容而不是參數。或者說是管道沒法正確傳遞到後面命令的參數位:(#echo ‘--help’| cat ,區別於#echo ‘--help’| xargs cat )orm
鑑於管道功能上的侷限,因此xargs的做用就顯現出來了:字符串
ƒ Xargs實現的是將管道傳輸過來的stdin進行處理後,傳遞到命令的參數上。即xargs完成了兩個動做:A.處理管道傳輸過來的stdin B.將處理後的stdin傳遞到正確的位置上it
④ Xargs的做用不只僅限於簡單的stdin傳遞到命令的參數位。它還能夠將stdin或者文件stdin分割成批,每一個批中有不少分割片斷,而後將這些片斷按批交給xargs後面的命令進行處理。io
⑤ Xargs默認其後面的命令是echo(「echo ‘a.txt’| xargs 」= 」echo ‘a.txt’| xargs echo「)而空格是其默認的定界符。class
⑥ Xargs會把管道傳遞過來的stdin裏的換行符,空白換成空格取代,造成一行做爲總體輸出:
[root@jmtom tmp]# cat c.txt
a.txt
b.txt
[root@jmtom tmp]# cat c.txt | xargs
a.txt b.txt
即:若是不指定分批選項(-i,-L,-n),Xargs的一整行結果將做爲一個總體輸出,而不是分隔開的!
⑦ Xargs一些比較經常使用的選項:
分割選項:-d ,-0 | 分批選項: -n,-L,-i/-I | 使用-p或-t來觀察命令的執行過程
分割選項 -d, -0:分割前會對stdin分批作一個分行動做,而後才進行分割
-d 指定分隔符
[root@jmtom testfile]# cat list.txt
a1.bak,a2.bak,a3.bak,a4.bak
[root@jmtom testfile]# cat list.txt | xargs -d','
a1.bak a2.bak a3.bak a4.bak
<——分割後輸出會多出分行符,會對後續的命令有影響
[root@jmtom testfile]# cat list.txt | xargs -d',' cat
this is a1
this is a2
this is a2.
this is a3
this is a3.
this is a3..
cat: a4.bak
: 沒有那個文件或目錄<——這裏就由於分割輸出多出的那一空行致使a4.bak文件沒法讀出
[root@jmtom testfile]#
正確的命令應該爲:cat list.txt | xargs -d',' |xargs cat
-0 指定固定的\0做爲分隔符。
其實xargs -0就是特殊的xargs -d的一種,它等價於xargs -d"\0"。
(‘\0’表示字符串結束,即字符串都是以’\0’結束的)
若是使用xargs -0時不指定分批選項(-n、-L、-i),則處理後的結果將做爲一個總體輸出。
[root@jmtom testfile]# ls | xargs
a1.bak a2.bak a3.bak a4.bak a5.bak a8.bak a9.bak list1.txt list.txt
[root@jmtom testfile]# ls | xargs -0
a1.bak
a2.bak
a3.bak
a4.bak
a5.bak
a8.bak
a9.bak
list1.txt
list.txt
[root@jmtom testfile]#
若是指定了分批選項,但沒有檢測到null字符,則整個結果將稱爲一個不可分割總體,這時使用分批選項是徹底無心義的。
[root@jmtom testfile]# ls | xargs -0 -n 3
a1.bak
a2.bak
a3.bak
a4.bak
a5.bak
a8.bak
a9.bak
list1.txt
list.txt
[root@jmtom testfile]#
若是指定了分批選項,而且檢測到了null字符,則以\0位的空格分段劃批,這時使用-n、-L或-i的結果是同樣的
[root@jmtom testfile]# ls |tr "\n" "\0"| xargs -0 -n 3
a1.bak a2.bak a3.bak
a4.bak a5.bak a8.bak
a9.bak list1.txt list.txt
[root@jmtom testfile]# ls |tr "\n" "\0"| xargs -0 -L 3
a1.bak a2.bak a3.bak
a4.bak a5.bak a8.bak
a9.bak list1.txt list.txt
[root@jmtom testfile]#
find -print0能夠輸出\0字符 ,因此會和xargs -0 結合一塊兒來用
分批選項:-n,-L,-i/-I: 分批用於指定每次傳遞多少個分段(參數)。
-i選項優先級最高,-L選項次之,-n選項優先級最低。
多個分批選項同時指定時,高優先級的選項會覆蓋低優先級的選項。也就是說這時候指定低優先級的選項是無心義的。
-n 該選項表示將xargs生成的命令行參數,每次傳遞幾個參數給其後面的命令執行
-L 和-n選項相似,惟一的區別是-L永遠是按段分段劃批,而-n在和獨立的xargs一塊兒使用是按空格分段劃批的。
-i 選項在邏輯上用於接收傳遞的分批結果。
-I 和-i是同樣的,只是-i默認使用大括號做爲替換符號,-I則能夠指定其餘的符號、字母、數字做爲替換符號,可是必須用引號包起來。
實例:
[root@jmtom testfile]# ls
a1.bak a2.bak a3.bak a4.bak a5.bak a8.bak a9.bak list1.txt list.txt my note.log
[root@jmtom testfile]# ls |xargs -n3 <-- 這裏-n以空格分段劃批
a1.bak a2.bak a3.bak
a4.bak a5.bak a8.bak
a9.bak list1.txt list.txt
my note.log
[root@jmtom testfile]#
[root@jmtom testfile]# ls |xargs -d'k' -n3 <-- -n跟-d配合使用,按有‘k’段分批
a1.ba
a2.ba
a3.ba
a4.ba
a5.ba
a8.ba
a9.ba
list1.txt
list.txt
my note.log
[root@jmtom testfile]#
----------------------- ------------------- -------------- -----------------------
[root@jmtom testfile]# ls | xargs -n1
a1.bak
a2.bak
a3.bak
a4.bak
a5.bak
a8.bak
a9.bak
list1.txt
list.txt
my <-- -n這裏是以空格爲段劃批,這裏的my不是存在的文件名
note.log <-- 「my note.log」纔是正確的文件名
[root@jmtom testfile]# ls | xargs -L1
a1.bak
a2.bak
a3.bak
a4.bak
a5.bak
a8.bak
a9.bak
list1.txt
list.txt
my note.log <-- -L這裏是一直以段爲段劃批
[root@jmtom testfile]#
------ ----------- ---------------- ------------
-i 選項在邏輯上用於接收傳遞的分批結果。
即若是不使用-i,則默認是將分割後處理後的結果總體傳遞到命令的最尾部。而用了-i能夠傳遞多個參數位,而不是僅僅最尾端的參數位。例如重命名備份的時候在每一個傳遞過來的文件名加上後綴.bak,這須要兩個參數位。
使用xargs -i時以大括號{}做爲替換符號,傳遞的時候看到{}就將被結果替換。能夠將{}放在任意須要傳遞的參數位上,若是多個地方使用{}就實現了多個傳遞。
[root@jmtom one]# touch day{1..7}
[root@jmtom one]# ls
day1 day2 day3 day4 day5 day6 day7
[root@jmtom one]# ls | xargs -i mv {} {}.bak <-- 完成了兩個參數位的傳遞
[root@jmtom one]# ls
day1.bak day2.bak day3.bak day4.bak day5.bak day6.bak day7.bak
[root@jmtom one]#
-I只是能夠自定義其替換符號:
[root@jmtom one]# ls | xargs -Ix mv x x.bak <-- 跟上面的命令效果同樣
[root@jmtom testfile]# ls | xargs -L3
a1.bak a2.bak a3.bak
a4.bak a5.bak a8.bak
a9.bak list1.txt list.txt
my note.log
------ ------------- -------------
體會一下有-i和沒有-i的區別:
[root@jmtom testfile]# ls | xargs -L3 -i cat {}
this is a1
this is a2
this is a2.
this is a3
this is a3.
this is a3..
this is a4
this is a4.
this is a4..
this is a4...
a1.bak,a2.bak
a3.bak,a4.bak
a5.bak,a8.bak
a9.bak
a1.bak,a2.bak,a3.bak,a4.bak
i am log of my note
[root@jmtom testfile]# ls | xargs -L3 cat
this is a1
this is a2
this is a2.
this is a3
this is a3.
this is a3..
this is a4
this is a4.
this is a4..
this is a4...
a1.bak,a2.bak
a3.bak,a4.bak
a5.bak,a8.bak
a9.bak
a1.bak,a2.bak,a3.bak,a4.bak
cat: my: 沒有那個文件或目錄
cat: note.log: 沒有那個文件或目錄 <-- 可見沒有-i傳遞的參數會被誤解分割了
[root@jmtom testfile]#
使用-p或-t來觀察命令的執行過程
[root@jmtom testfile]# ls | xargs -L3 -p cat
cat a1.bak a2.bak a3.bak ?...yes <-- 詢問是否這樣執行命令,輸入y或yes將執行
cat a4.bak a5.bak a8.bak ?...this is a1
this is a2
this is a2.
this is a3
this is a3.
this is a3..
yes <--- 同上
cat a9.bak list1.txt list.txt ?...this is a4
this is a4.
this is a4..
this is a4...
yes <-- 同上
cat my note.log ?...a1.bak,a2.bak
a3.bak,a4.bak
a5.bak,a8.bak
a9.bak
a1.bak,a2.bak,a3.bak,a4.bak
yes <-- 同上
cat: my: 沒有那個文件或目錄 <-- 這裏就看出來分批傳遞到這裏後出問題了由於cat無法對「my note.log」文件處理,它分解成了my和note.log兩個不存在的文件,因此提示沒有那個文件或者目錄
cat: note.log: 沒有那個文件或目錄
[root@jmtom testfile]#
[root@jmtom testfile]# ls | xargs -L3 -i -p cat {}
cat a1.bak ?...y
cat a2.bak ?...this is a1
y
cat a3.bak ?...this is a2
this is a2.
y
cat a4.bak ?...this is a3
this is a3.
this is a3..
y
cat a5.bak ?...this is a4
this is a4.
this is a4..
this is a4...
y
cat a8.bak ?...y
cat a9.bak ?...y
cat list1.txt ?...y
cat list.txt ?...a1.bak,a2.bak
a3.bak,a4.bak
a5.bak,a8.bak
a9.bak
y
cat my note.log ?...a1.bak,a2.bak,a3.bak,a4.bak
y
i am log of my note
[root@jmtom testfile]#
這裏# ls | xargs -L3 -i -p cat {}就能夠看出來-i是按邏輯上一個一個傳遞參數(-i按分段來傳遞,沒法按批來傳遞),這裏-i的優先權大於-L,因此這裏的-L是無心義的。
⑧ xargs主要是爲find服務的
咱們要刪除一個帶空格的文件:
[root@jmtom one]# touch a b c "my note.log"
[root@jmtom one]# ls
a b c my note.log
[root@jmtom one]#
[root@jmtom one]# find . -name *.log
./my note.log
[root@jmtom one]# find . -name *.log | xargs rm -fr <- 這樣是無法刪除的,rm只是解讀爲刪除./my 的文件,並非./my note.log這個文件
[root@jmtom one]# ls
a b c my note.log
[root@jmtom one]# find . -name *.log -print0| xargs -0 rm -fr <-- 一般用find -print0來結合xargs -0 來處理,但沒有通用性,別的命令沒法用這個方法
[root@jmtom one]# ls
a b c
[root@jmtom one]# touch "my note.log"
[root@jmtom one]# find . -name *.log | xargs -i rm -fr "{}" <-- 這種方法相對會有通用性,別的命令也能使用
[root@jmtom one]# ls
a b c
[root@jmtom one]#
Ps:
Linux命令通常能夠從兩個地方讀取要處理的內容,一個是經過命令行參數,二是經過標準輸入。可是不少命令的設計是先從命令行參數中獲取參數,而後纔是從標準輸入stdin中讀取。(大多數命令有一個參數 「-」,來表示從標準輸入中讀取)
[root@jmtom tmp]# cat a.txt
this is a.txt
i love u !
u love me ?
[root@jmtom tmp]# echo "my love" | cat a.txt <- 只會先讀取命令行參數因此只讀了a.txt
this is a.txt
i love u !
u love me ?
[root@jmtom tmp]# echo "my love" | cat a.txt - <- 這裏多加了一個橫槓,表stdin,因此先讀了a.txt再讀了echo的內容(注意前後順序)
this is a.txt
i love u !
u love me ?
my love
[root@jmtom tmp]# echo "my love" | grep 'love' a.txt
i love u !
u love me ?
[root@jmtom tmp]# echo "my love" | grep 'love' a.txt -
a.txt:i love u !
a.txt:u love me ?
(標準輸入):my love
[root@jmtom tmp]#