xargs將stdin轉換為命令列引數
我們可以用管道將一個命令的stdout(標準輸出)重定向到另一個命令的stdin(標準輸入)。例如:
$cat foo.txt | grep “test”
但是,有些命令只能以命令列引數的形式接受收據,而無法通過stdin接受資料流。在這種情況下,我們沒法用管道來提供那些只有通過命令列引數才能提供的資料。
只有另闢蹊徑。xargs是一個很有用的命令,它擅長將標準輸入資料轉換成命令列引數。
單行命令是一個命令序列,各命令之間不使用分號,而是使用管道操作符進行連線。精心編寫的單行命令可以更高效、更簡捷地完成任務。就文字處理而言,需要具備紮實的理論和實踐才能夠寫出適合的單行命令解決方法。xargs就是構建單行命令的重要元件之一。
xargs命令用該緊跟在管道操作符之後。它以標準輸入作為主要的源資料流。
command | xargs
----->>
xargs命令能將stdin接收到的資料重新格式化,再將其作為引數提供給其他命令。
xargs如何格式化資料:
-d選項,指明定界符
-n選項,指明每行最大的引數數量n
範例:將多行輸入轉換成單行輸出
只需將換行符移除,在用” ”(空格)進行替換,就可以實現。xargs預設將空格作為定界符。xargs沒有指定引數時,預設能將換行符替換成空格。
$cat example.txt
1 2 3 4 5 6
7 8 9 10
11 12
$catexample.txt | xargs
1 2 3 4 5 6 7 8 9 10 11 12
範例:將單行輸入轉換成多行輸出
$cat examole.txt | xargs -n 3
1 2 3
4 5 6
7 8 9
10 11 12
$echo “splitXsplitXsplitXsplit” | xargs -d X
split splitsplit split
$echo “splitXsplitXsplitXsplit” | xargs -d X –n 2
split split
split split
xargs的初衷是將引數列表轉換成小塊分段傳給其他命令,以避免參數列表過長。
編制一個定製版的echo來更好的理解xargs。
#!/bin/bash
#myecho.sh
echo $*’#’
當引數被傳遞給myecho.sh後,它會將這些引數打印出來,並以#字元作為結尾。例如:
$./myecho.sh arg1 arg2
arg1 arg2#
看下面問題:
有一個包含引數列表的檔案(每行一個引數)。
每次提供一個引數:
./myecho.sh arg1
./myecho.sh arg2
./myecho.sh arg3
每次提供多個引數:
./myecho.sh arg1 arg2
./myecho.sh arg3
一次性提供:
./myecho.sh arg1 arg2 arg3
上面的問題,也可以用xargs實現。我們將引數儲存到args.txt。
$cat args.txt
arg1
arg2
arg3
$cat args.txt | xargs -n 1 ./myecho.sh
arg1#
arg2#
arg3#
通過#號,可以知道myecho.sh運行了3次。
$cat args.txt | xargs -n 2 ./myecho.sh
arg1 arg2#
arg3#
#catargs.txt | xargs ./myecho.sh
arg1 arg2 arg3#
xargs不加引數時,預設將換行符替換成空格。就好像是預設,為這種,從引數列表檔案中獲取引數提供方便服務的。(想想,如果沒有這種預設服務,那麼想要將擁有多行文字的args.txt中的引數一次性提取,你會怎麼做?)
上面例子中,我們直接為myecho.sh提供引數。這些引數都源於args.txt檔案。但實際上除了它們外,我們還需要一些固定不變的命令引數。思考下面這種命令格式:
./myecho.sh -p arg1 –l
在上面的命令執行過程中,arg1是唯一的可變文字,其餘部分保持不變。我們應該從args.txt中讀取引數,並按照下面的方式提供給命令:
./myecho.sh -p arg1 -l
./myecho.sh -p arg2 -l
./myecho.sh -p arg3 -l
xargs有一個選項-I,可以提供上面這種形式的命令執行序列。我們可以用-I執行一個替換字串,這個字串在xargs擴充套件時會被替換掉。當-I與xargs結合使用,對於每一個引數命令都會執行一次。
$cat args.txt | xargs -I {} ./myecho.sh -p {} -l
-p arg1 -l#
-p arg2 -l#
-p arg3 -l#
結合find使用xargs:
兩者結合使用可以讓任務變得更輕鬆。不過,人們通常卻是以一種錯誤的組合方式使用它們。例如:
$find . –type f -name “*.txt” -print | xargs rm -f
這樣做很危險。有時可能會刪除不必要刪除的檔案。我們沒法預測分隔find命令輸出結果的定界符究竟是’\n’還是’ ‘(空格)。很多檔名中都可能會包含空格符,而xargs很可能會誤認為它們是定界符(例如,hell text.txt會被xargs誤認為hell和text.txt)。
只要我們把find的輸出作為xargs的輸入,就必須將-print0與find結合使用,以字元null來分隔輸出。
用find匹配並列出所有.txt檔案,然後用xargs將這些檔案刪除:
$find . –type f -name “*.txt” -print0 | xargs -0 rm -f
刪除所有txt檔案。xargs -0將\0作為輸入定界符。
統計所有C程式檔案的行數:
$find code_path -type -f -name “*.c” -print0 | xargs -0 wc -l