本文為部落格園作者所寫: 一寸HUI,個人部落格地址:https://www.cnblogs.com/zsql/
你有批量kill作業嗎?有因為刪除資料夾的內容太多而報錯嗎?-bash: /bin/rm: Argument list too long,查詢出來的檔案怎麼直接刪除呢?批量執行?併發執行?如果有這樣的需求的話,就可以開始學習xargs命令了,本文主要的思路先提供一些簡單的使用場景,然後再對xargs命令原理和使用進行闡述。
一、簡單使用場景
1.1、使用場景
- 傳遞引數,從而組合多個命令
- 分隔資料,避免引數過長
- 不支援管道的命令
1.2、具體例項
1.1、批量刪除hive使用者的所有程式
ps aux | grep ^hive | grep -v grep | awk '{print $2}' | xargs kill -9
1.2、分批次刪除logs目錄下2020年的所有檔案,每批為10個
cd /logs && ls | grep *2020* | xargs -n 10 rm -fr
ls /logs | sed "s:^:`pwd`/:" | grep *2020* | xargs -n 10 rm -fr
1.3、結合find命令進行處理文件,find命令可以檢視:linux之find命令詳解
find . -name *.log -print0 | xargs rm -f #查詢當前目錄下的所有log檔案,並刪除
find ./ -type f -name "*.txt" | xargs -i cp {} /tmp/ #查詢txt檔案,並複製到/tmp目錄下
find ./ -type f -name "*.log" | xargs -i -t tar -zcvf {}.tar.gz {} #壓縮日誌檔案
1.4、批量下載
cat urls.txt | xargs wget
1.5、如果打通了ssh免密,假如有ip:192.168.88.130,192.168.88.131
echo "192.168.88.130,192.168.88.131" | xargs -n 1 -P 2 -I __ip__ scp root@__ip__:/var/log/cron ./__ip__.cron #把這兩個機器的cron日誌複製到本地,取名為${ip}.cron
二、原理和使用
2.1、使用語法
[root@lgh~]# xargs --help Usage: xargs [-0prtx] [--interactive] [--null] [-d|--delimiter=delim] [-E eof-str] [-e[eof-str]] [--eof[=eof-str]] [-L max-lines] [-l[max-lines]] [--max-lines[=max-lines]] [-I replace-str] [-i[replace-str]] [--replace[=replace-str]] [-n max-args] [--max-args=max-args] [-s max-chars] [--max-chars=max-chars] [-P max-procs] [--max-procs=max-procs] [--show-limits] [--verbose] [--exit] [--no-run-if-empty] [--arg-file=file] [--version] [--help] [command [initial-arguments]]
2.2、原理說明
在1.1中我們說了xargs使用的三個場景,一個是引數太長導致命令不能執行,就像rm一樣,如果rm -rf /log/*,正如log目錄下有很多很多個檔案,這樣就會出現/bin/rm: Argument list too long這樣的錯誤,那為啥使用xargs就能刪除了呢,因為xargs預設會把引數擷取分批進行執行,這裡使用了xargs的分割資料和傳遞引數原理,還有就是有些命令並不支援管道符,像ls命令,但是又想使用一行命令搞定,這樣就可以使用xargs配合使用了。比如使用命令:echo text.txt | xargs cat,這樣可以把text.txt傳遞給cat命令作為引數,這樣就可以檢視該檔案了,也就是說xargs完成了兩個行為:處理管道傳輸過來的stdin;將處理後的傳遞到正確的位置上,還可以將stdin或者檔案stdin分割成批,每個批中有很多分割片段,然後將這些片段按批交給xargs後面的命令進行處理,可能看到這裡會有點懵逼,那簡單點就是:xargs處理的優先順序或順序了:先分割,再分批,然後傳遞到引數位。
舉個例子:假如你有一個蛋糕,你要分給10個孩子去吃,首先第一步要進行切蛋糕(分割)那怎麼切呢,切10塊還是20塊或者其他呢?所以這裡就會存在切蛋糕方式的選擇(分割方式),切好蛋糕後,小孩子都在不同的地方,你是選擇每次送一塊蛋糕呢,還是一次送兩塊呢(這就是分批,每批次傳送多少個),送也要找到小孩的位置才能送到他手上吧,(這就是把分好批的檔案或資料傳遞到命令指定的引數的位置),我想大家應該比較容易理解這個了,如果你還是沒能理解,多看幾遍:xargs處理的優先順序或順序了:先分割,再分批,然後傳遞到引數位,然後繼續看下面的引數例子就懂了
2.3、引數詳解
2.3.1、分割引數
分割有三種方法:獨立的xargs、xargs -d和xargs -0,後兩者可以配合起來使用,既然都可以用來分割,那我們看看分割的方式:
1、xargs分割:將接收到的stdout處理後傳遞到xargs後面的命令引數位,不寫命令時預設的命令是echo,會對空格、tab、換行符,反斜線等進行分割
[root@lgh test]# echo -e "a b c \n dd \t y" a b c dd y [root@lgh test]# echo -e "a b c \n dd \t y" | xargs #預設會使用echo命令輸出,這裡的換行符和空格以及製表符都被作為分隔符用來分割了 a b c dd y [root@lgh test]# echo -e "a b c \n dd \t y" | xargs echo a b c dd y
將所有空格、製表符和分行符都替換為空格並壓縮到一行上顯示,這一整行將作為一個整體,這個整體的所有空格屬性繼承xargs處理前的符號屬性(大概理解為,把這些分割好後用自己的所要的“段”替代,幹掉別人的心腹(分隔符),換成自己的心腹)
2、xargs -d分割:可以指定分段符,可以是單個符號、字母或數字。如指定字母o為分隔符:xargs -d"o"
[root@lgh test]# echo -e "a bd\n cod \n dod \t y" a bd cod dod y [root@lgh test]# echo -e "a bd\n cod \n dod \t y" |xargs -d 'o' #使用o進行分割,但是這樣可能看的不是很清楚 a bd c d d d y
這樣看可能就清楚了:
[root@lgh test]# echo -e "a bd\n cod \n dod \t y" |xargs -p -n 1 -d "o" #-p引數互動引數,-n 1執行每批的個數,這些後面會說到 /bin/echo a bd c ?... #列印第一批 /bin/echo d d ?... #列印第二批 /bin/echo d y ?... #列印第三批 /bin/echo ?...
從上就可以看出來是指定的字元"o"進行分割了,使用xargs -d分割,會忽略空格、製表符、分行符等這些符號,會把這些當做內容保留下來,如上面的換行符都有保留下來,只有指定的"o"才是分割符
3、xargs -0分割:可以處理接收的stdin中的null字元(\0),其實可以理解是xargs -d的一種特列,等價於xargs -d "\0"
[root@mvxl2685 test]# echo -e "1\tbbb \n uu\0dddd"
1 bbb
uudddd
[root@mvxl2685 test]# echo -e "1\tbbb \n uu\0dddd" | xargs -0
1 bbb
uu dddd
[root@mvxl2685 test]# echo -e "1\tbbb \n uu\0dddd" | xargs -0 -p -n 1
/bin/echo 1 bbb
uu ?... #第一批
/bin/echo dddd
?... #第二批
/bin/echo ?...
上面三種分割方式,使用最多的也就是預設的xargs了
分割行為 |
特殊符號處理方式 |
分段方法 |
配合分批選項 |
分批方法 |
xargs |
空格、製表符、分行符替換為空格,引號和反斜線刪除。處理完後只有空格。如果空格、製表符和分行符使用引號包圍則可以保留 |
結果繼承處理前的符號性質(文字符號還是標記意義符號)。 |
-n |
以分段結果中的每個空格分段,進而分批。不管是文字還是標記意義的空格,只要是空格 |
-L、-i |
以標記意義上的空格分段,進而分批 |
|||
不指定 |
結果作為整體輸出 |
|||
xargs -d |
xargs -d 不處理文字意義上的符號,所有標記意義上的符號替換為換行符\n,將-d指定的分割符替換為標記意義上的空格。 結果中除了最後的空行和-d指定的分割符位的分段空格,其餘全是文字意義上的符號 |
按照-d指定的符號進行分段,每個段中可能包含文字意義上的空格、製表符、甚至是分行符。 |
-n、-L、-i |
以標記意義上的符號(即最後的空行和-d指定分隔符位的空格)分段,進而分批。分段結果中保留所有段中的符號,包括製表符和分行符。 |
不指定 |
結果作為整體輸出 |
|||
xargs -0 |
不處理文字意義上的符號,將非\0的標記意義上的符號替換為\n,將\0替換為空格。 結果中除了最後空行和\0位的空格,其餘都是文字意義上的符號 |
以替換\0位的空格分段,每個段中可能包含文字意義上的空格、製表符、甚至是分行符。 如果沒檢測到\0,則只有一個不可分割的段。 |
-n、-L、-i |
檢測到\0時,以標記意義上的符號(即最後的空行和\0位的空格)分段,進而分批。分段結果中保留所有段中的符號,包括製表符和分行符。 |
未檢測到\0時,整個結果作為不可分割整體,使用分批選項是無意義的 |
||||
不指定 |
結果作為整體輸出 |
2.3.2、分批引數
上面一節中我們知道怎麼切蛋糕了(分割),接下來我們就怎麼把這些分割好的內容組裝成批次。可以使用-n和-L兩個引數,那具體他們有什麼區別呢?請繼續往下看:
1、使用-n分批
假如有資料夾test:
[root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:33 a -rw-r--r-- 1 root root 0 Dec 4 14:33 b -rw-r--r-- 1 root root 0 Dec 4 14:33 c -rw-r--r-- 1 root root 0 Dec 4 14:33 dd -rw-r--r-- 1 root root 0 Dec 4 14:33 gg -rw-r--r-- 1 root root 0 Dec 4 14:33 u t.txt #這是個特殊檔案,有空格的檔名 -rw-r--r-- 1 root root 0 Dec 4 14:33 uu
接下我們使用-n分批會有怎樣的效果呢?
[root@lgh test]# ls | xargs -n 2 #每兩個作為一個批次 a b c dd gg u #這裡把u t.txt檔案拆到兩個批次中了,這並不是我們想要的 t.txt uu
xargs -n分兩種情況:和獨立的xargs一起使用,這時按照每個空格分段劃批;和xargs -d或xargs -0一起使用,這時按段分批,即不以空格、製表符和分行符分段劃批
2、使用-L分批
[root@lgh test]# ls | xargs -L 2 #每兩個作為一個批次 a b c dd gg u t.txt #這裡就沒有拆分u t.txt檔案 uu
-n選項類似,唯一的區別是-L永遠是按段劃批,而-n在和獨立的xargs一起使用時是按空格分段劃批的
2.3.3、位置傳遞引數
xargs -i和xargs -I選項在邏輯上用於接收傳遞的分批結果,如果不使用這兩個選項,則預設是將分割後處理後的結果整體傳遞到命令的最尾部,有時候可能需要到多個位置,或者不是最後一個位置,例如cp命令一樣,所以這兩個引數很重要。
使用xargs -i時以大括號{}作為替換符號,傳遞的時候看到{}就將被結果替換。可以將{}放在任意需要傳遞的引數位上,如果多個地方使用{}就實現了多個傳遞
假如有目錄test:
[root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:51 10.log -rw-r--r-- 1 root root 0 Dec 4 14:51 1.log -rw-r--r-- 1 root root 0 Dec 4 14:51 2.log -rw-r--r-- 1 root root 0 Dec 4 14:51 3.log -rw-r--r-- 1 root root 0 Dec 4 14:51 4.log -rw-r--r-- 1 root root 0 Dec 4 14:51 5.log -rw-r--r-- 1 root root 0 Dec 4 14:51 6.log -rw-r--r-- 1 root root 0 Dec 4 14:51 7.log -rw-r--r-- 1 root root 0 Dec 4 14:51 8.log -rw-r--r-- 1 root root 0 Dec 4 14:51 9.log
現在需要把它們全部備份起來,程式設計*.log.bak檔案
[root@lgh test]# ls | xargs -i mv {} {}.bak #這裡使用-i接收,然後使用{}指定位置 [root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:51 10.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 1.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 2.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 3.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 4.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 5.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 6.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 7.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 8.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 9.log.bak
-I則可以指定其他的符號、字母、數字作為替換符號,例如xargs -I
[root@lgh test]# ls | xargs -I bb mv bb bb.I #這裡使用-I引數指定bb為接收替代符 [root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:51 10.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 1.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 2.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 3.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 4.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 5.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 6.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 7.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 8.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 9.log.bak.I
注意:-i、-L、-n這三個引數在一起,都會被最後一個覆蓋,也就是一起使用的時候,只有最後一個生效
2.3.4、其他引數
上面已經把最重要的一些引數介紹完了,我們看看其他引數
1、-p和-t:互動引數,可以用於前期不確定執行過程,用來測試自己寫的程式碼是否符合最終的執行命令
-p是詢問是否列印,y鍵表示列印,回車表示不列印
[root@lgh test]# ls | xargs -n 3 -p /bin/echo 10.log.bak.I 1.log.bak.I 2.log.bak.I ?...y #詢問列印,按下y /bin/echo 3.log.bak.I 4.log.bak.I 5.log.bak.I ?...10.log.bak.I 1.log.bak.I 2.log.bak.I #列印出上一次詢問的值,然後繼續詢問下一個批次是否列印,按下回車,不列印輸出 /bin/echo 6.log.bak.I 7.log.bak.I 8.log.bak.I ?... /bin/echo 9.log.bak.I ?...
-t是先把執行的語句列印出來,然後把要輸出的內容列印出來
[root@lgh test]# ls | xargs -n 3 -t /bin/echo 10.log.bak.I 1.log.bak.I 2.log.bak.I #列印執行的語句 10.log.bak.I 1.log.bak.I 2.log.bak.I #列印執行語句的結果 /bin/echo 3.log.bak.I 4.log.bak.I 5.log.bak.I 3.log.bak.I 4.log.bak.I 5.log.bak.I /bin/echo 6.log.bak.I 7.log.bak.I 8.log.bak.I 6.log.bak.I 7.log.bak.I 8.log.bak.I /bin/echo 9.log.bak.I 9.log.bak.I
2、-P:批量執行引數(併發,一起執行)哈哈,反正就是同時執行
在執行某一個命令的時候,後面很多引數的時候,例如:rm log/* 會對log下的每一個目錄進行依次刪除,就算使用xargs的分批執行,還是一個一個執行的,並不會提高效率,接下來該-P引數出場了
"-P N"選項可以指定並行處理的程式數量為N。不指定"-P"時,預設為1個處理程式,也就是序列執行。指定為0時,將盡可能多地開啟程式數量
[root@lgh ~]# time echo {1..3} | xargs -n 1 sleep #不使用-P,並每個批次為1,總共的執行時間為6秒 real 0m6.005s user 0m0.001s sys 0m0.001s [root@lgh ~]# time echo {1..3} | xargs -n 3 sleep #不使用-P,每個批次為3,總共執行時間為6秒,分批不能提高速度 real 0m6.003s user 0m0.000s sys 0m0.002s [root@lgh ~]# time echo {1..3} | xargs -n 3 -P 3 sleep #使用-P,每個批次為3,說明只有一個批次,所以一個執行緒需要一次執行所有的命令,所以還是6秒,沒有達到併發的效果 real 0m6.003s user 0m0.001s sys 0m0.000s [root@lgh ~]# time echo {1..3} | xargs -n 1 -P 3 sleep #使用-P,每個批次為1,所以可以同時執行命令,執行時間為3秒 real 0m3.003s user 0m0.001s sys 0m0.001s
很多時候,執行大量命令的時候可以使用-P提高效率
2.4、總結
xargs命令很強大,你值得擁有!!!如果使用的得當不僅可以提高逼格,還可以提高效率,能夠做一些原本命令不能做到的事情,好好學號xargs何樂而不為呢?
xargs的總結:分割(xargs,xargs -d,xargs -0)、分批(-n,-L)、傳遞到指定位置(-i,-I)
參考:
https://www.cnblogs.com/f-ck-need-u/p/5925923.html#auto_id_9