咱們能夠用管道將一個命令的stdout(標準輸出)重定向到另外一個命令的stdin(標準輸入),如:bash
$ cat foo.txt | grep "test"
解析:查看foo.txt文件並打印出含有test的行。命令行
可是有些命令只能以命令行參數的形式接受數據,而沒法經過stdin接受數據流。在這種狀況下,咱們無法用管道來提供哪些只有經過命令行參數才能提供的數據。code
那如今就該xargs上場了,它擅長將標準輸入數據轉換成命令行參數。字符串
預備知識:源碼
xargs命令應該緊跟在管道操做符以後,以標準輸入做爲主要的源數據流,它使用stdin並經過提供命令行參數來執行其餘命令。xargs命令把從stdin接收到的數據從新格式化,再將其做爲參數提供給其餘命令。it
1、將多行輸入轉換成單行輸出test
$ cat foo.txt # 樣例文件 1 2 3 3 4 5 7 8 9 10 11 12 $ cat foo.txt | xargs 1 2 3 4 5 6 7 8 9 10 11 12
2、 將單行輸入轉換爲多行輸出擴展
$ cat foo.txt | xargs -n 3 1 2 3 4 5 6 7 8 9 10 11 12
解析:指定每行最大的參數數量n,將任何來自stdin的文本劃分紅多行,每行n個參數。file
xargs默認的定界符是空格,咱們本身能夠來設置定界符,用-d選項爲輸入指定一個定製的定界符。循環
$ echo "splitXsplitXsplitXsplit" | xargs -d X split split split split
結合-n選項,咱們能夠將輸入劃分紅多行,每行包含兩個參數。
$ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2 split split split split
3、如何將參數傳遞給命令 讀取stdin(標準輸入),將格式化參數傳遞給命令
編寫一個小型的echo來更好的理解用xargs提供命令行參數的方法:
#!/bin/bash #filename: cecho.sh echo $@ "#"
當參數傳遞給cecho.sh後,它將會把這些參數打印出來,並以# 字符結尾
$ ./eceho.sh arg1 arg2 arg1 arg2 #
那麼,咱們如今想把這個命令執行屢次, 每次使用一個參數,難道咱們只能一遍一遍的執行?如今,咱們有一個名爲args.txt的參數列表文件,內容爲:
arg1 arg2 arg3
咱們來看下面的代碼
$ cat args.txt | xargs -n 1 ./cecho.sh arg1 # arg2 # arg3 #
每次執行須要X個參數的命令時,使用:
$ cat args.txt | xargs -n 2 ./cecho.sh arg1 arg2 # arg3 #
可是有些時候,咱們須要一些不變的參數,看下面這種命令格式:
$ ./cecho -p arg1 -1
在上面的命令執行過程當中,arg1 是惟一可變的參數,其他部分都保持不變,咱們能夠從文件(argx.txt)中讀取參數,按照下面的方式提供給命令:
./cecho -p arg1 -1 ./cecho -p arg2 -1 ./cecho -p arg3 -1
xargs有個一個-I(大寫的i)的選項,能夠提供上面這種形式的命令執行序列。咱們用-I指定替換字符串,這個字符串在xargs擴展(傳遞給命令)時會被替換掉。若是將-I與xargs結合使用,對於每個參數,命令都會被執行一次。
$ cat args.txt | xargs -I {} ./cecho -p {} -1 -p arg1 -1 # -p arg2 -1 # -p arg3 -1 #
-I {}指定了替換字符串。對於每個命令參數,字符串{}都會被從stdin讀取到的參數所替換掉。使用-I的時候,命令會以循環的方式執行。若是有3個參數,那個命令就會被執行3次。在每一次執行的時候{}都會被替換爲相應的參數。
xargs常常會與find一塊兒使用,不過人們一般都會以一種錯誤的方式去使用它們。
$ find . type -f -name "*.txt" -print | xargs rm -f {} \;
咱們無法預測find命令輸出的結果的定界符是什麼('\n'或' ')。不少文件都有可能包含空格符(' '),所以xargs極可能會誤認爲它們是定界符(例如:hell text.txt會被xargs理解爲hello和text.txt兩個文件)。
只要咱們把find的輸出做爲xargs的輸入,就必須將-print0與find結合使用,以字符null('\0')來分隔輸出。
用find匹配並列出全部的.txt文件,而後用xargs將這些文件刪除:
$ find . -type f -name "*.txt" -print0 | xargs -0 rm -f {} \;
這樣就能夠刪除全部的.txt文件,xargs -0將\0做爲輸入的定界符。
統計源碼目錄下全部.sh的文件行數。
$ find . type f -name "*.sh" -print0 | xargs -0 wc -l