xargs命令_Linux xargs命令:一個給其他命令傳遞參數的過濾器


本文要為大家介紹的命令是 xargs,我們把它稱為護花使者,因為它總是樂於協助其他的命令來完成一些事情。下面一起來看看它是如何護花的。

xargs 是 execute arguments 的縮寫,它的作用是從標准輸入中讀取內容,並將此內容傳遞給它要協助的命令,並作為那個命令的參數來執行。

坊間有一種說法,將 xargs 解讀為乘號(x)和參數(args)的合體,很形象地表達了 xargs 的作用所在。

好了,我們一起來見識一下 xargs 的護花本領吧:

我們用ls命令列出當前路徑下的文件, 包括3個文件

[roc@roclinux ~]$ ls
china.txt  usa.txt japan.txt

我們通過xargs + ls的方式列出my.txt文件和your.txt文件

[roc@roclinux ~]$ echo "china.txt usa.txt" | xargs ls
china.txt usa.txt

可以很清晰地看到,xargs 將 echo 的輸出作為自己的標准輸入,並且將其傳遞給了 ls 命令,作為 ls 命令的參數來執行。
xargs 和管道不得不說的故事
為了能夠為大家解釋清楚 xargs 和管道的關系,我們這次選用了更加典型的 cat 命令來為大家舉例。

為什么選擇 cat 命令呢?眾所周知,cat 命令可以接收文件名作為參數,執行后會顯示出文件的內容。但是 cat 命令不能直接從標准輸入接收參數,正如下面的例子:

cat后面直接指定china.txt參數, 可以展示china.txt文件的內容

[roc@roclinux ~]$ cat china.txt
hello beijing

我們嘗試通過標准輸入把參數傳給cat, 結果卻只是顯示了文件名而已

[roc@roclinux ~]$ echo china.txt | cat
china.txt

從上面的例子中,我們可以得出下面的結論:
管道可以實現:將前面的標准輸出作為后面的“標准輸入”。
管道無法實現:將前面的標准輸出作為后面的“命令參數”。

這個時候,就要有請 xargs 這位護花使者了。xargs 所擅長的正是“將標准輸入作為其指定命令的參數”。說着有些拗口,但我相信大家懂的。

xargs果然不負眾望, 協助cat完成了使命

[roc@roclinux ~]$ echo china.txt | xargs cat
hello beijing

我們知道,xargs 會將前一個命令的標准輸出轉換成命令參數,但很多人可能不知道的是,xargs 的標准輸入中出現的“換行符、空格、制表符”都將被空格取代。下面來看一個帶有換行符的例子:

我們准備好了帶有換行的標准輸入

[roc@roclinux ~]$ echo -e "china.txt\njapan.txt"
china.txt
japan.txt

可見, 換行符和空格的作用一樣

[roc@roclinux ~]$ echo -e "china.txt\njapan.txt" | xargs cat
hello beijing
hello tokyo

上面的例子是一個比較簡單的場景,我們有時還會遇到更棘手的情況,一起來看一看。

當命令參數中包含了空格時,情況就會復雜很多,一起來看一個示例。

我們創建了3個日志文件, 且故意讓文件名稱中都含有空格

[roc@roclinux ~]$ for((i=0;i<3;i++)); do touch "test ${i}.log";done

我們列出創建的文件

test 0.log
test 1.log
test 2.log

我們來運行xargs命令, 發現報錯了

[roc@roclinux ~]$  find . -name '*.log' -print | xargs rm
rm: cannot remove ‘./test’: No such file or directory
rm: cannot remove ‘1.log’: No such file or directory
rm: cannot remove ‘./test’: No such file or directory
rm: cannot remove ‘0.log’: No such file or directory
rm: cannot remove ‘./test’: No such file or directory
rm: cannot remove ‘2.log’: No such file or directory

我們在當前目錄中創建了 3 個文件,文件名中間都含有空格。但當 find 命令獲取到的文件名經過 xargs 傳送給 rm 命令時,文件“./test 1.log”就變成了“./test”和“1.log”兩個文件了。即原本 3 個文件名剎那間就變成了 6 個文件名,而這 6 個文件其實並不存在,從而引發了錯誤。

這個錯誤的根源就在於 xargs 默認的分隔符是空格,如果我們能將 xargs 的分隔符改成其他符號,問題就迎刃而解了!

xargs 提供了-0選項,允許將 NULL 作為分隔符,而 find 命令也心有靈犀地提供了對應的選項來產生以 NULL 字符作為分隔符的輸出。

find 命令提供的對應方法是 -print0 選項,在文件名之后輸出 NULL,而不像 -print 選項那樣輸出換行符(換行符會被 xargs 替換成空格)。

正如我們所期待的,命令果然正常執行了,完美!

[roc@roclinux ~]$ find . -name '*.log' -print0 | xargs -0 rm -f

對了,要補充一點,xargs 的-0選項不僅可以將分隔符從默認的空格變成 NULL,還會將單引號、雙引號、反斜線等統統默認為是普通字符。所以說,-0選項特別適合處理命令參數中含有引號、空格、反斜線的情況。

如果你是一位 GEEK,希望掌握得更深入,那么我們就再補充一個知識點。除了可以使用-0選項外,其實還可以使用-d選項來指定任何一個符號作為分隔符。只是我們要格外慎重,避免我們所設定的那個分隔符恰好是我們命令參數中所包含的字符,那就會導致非預期的結果了。
讓護花使者聽我們的話
如果在前一個命令的標准輸出中,會有一些參數是你不希望或者不確定是否要傳送給后面命令的,這個時候我們就希望 xargs 在傳送參數前和我們確認一下。而-p選項恰好可以實現這個願望,我們可以輸入 y 或者 n 來選擇是否要執行當前命令:

[roc@roclinux ~]$ find . -type f |xargs -p rm -f
rm -f ./china.txt ./usa.txt ./japan.txt ?...n

上面的命令中,我們輸入了“n”,也就是不希望刪除這三個文件。不過,這樣的確認粒度太粗,我們希望的是更精細地確認,來試試-n選項吧:

[roc@roclinux 20160408]$ find . -type f |xargs -p -n 1 rm -f
rm -f ./china.txt ?...n
rm -f ./usa.txt ?...y
rm -f ./japan.txt ?...n

使用-n選項,可以讓 xargs 每次只處理 1 個參數,這樣做的好處是避免一次性刪除過多文件,萬一誤刪了不該刪除的文件,那麻煩就大了。
遇到就停止
xargs 已經足夠優秀了,可以幫助我們處理各種各樣的問題。但我們對 xargs 還有更加苛刻的要求,那就是當碰到某個特定的命令參數時,要求 xargs 立即終止並退出。

這個效果,我們可以使用-E選項來實現。

比如,我們正在處理一份日志文件 country.list 中的內容,將日志文件中的字符以空行作為分隔符依次 echo 出來,一旦遇到 korea 便終止退出:

[roc@roclinux ~]$ echo "china usa korea japan" > country.list
 
[roc@roclinux ~]$ cat country.list
china usa korea japan
 
[roc@roclinux ~]$ cat country.list | xargs -E 'korea' echo
china usa

可以看到當處理到 korea 的時候,xargs 機警地發現了狀況,於是,按照我們的要求,立即終止並退出了。好乖的 xargs 啊!
你可能一生都不會遇到的參數過長報錯
可能很多運維工程師都沒有遇到過“Argument list too long”這樣的報錯。但要想成為一名資深的運維工程師,了解它的原因和解決方法還是很有必要的。

我們來模擬一個這樣的場景,新建 10 萬個日志文件,並且嘗試用 rm 命令一次性刪除:

[roc@roclinux ~]$ for((i=0;i<100000;i++)); do touch test${i}.log;done
 
[roc@roclinux ~]$ rm $(find . -type f -name '*.log')
-bash: /bin/rm: Argument list too long

出現了“Argument list too long”報錯,這說明 rm 可接受的參數長度達到了極限。這其實並非 rm 的錯,而是系統限制了參數的長度。通過下面的命令可以查看到系統的參數長度限制值:

[roc@roclinux ~]$ getconf ARG_MAX
2621440

如果真的遇到了參數過長的問題,我們的應對方法其實有很多種,比如把文件手工分組以縮短參數的長度,但是這個方法並不優雅,而且費時費力。最優雅的方法當然就是借助 xargs 啦:

[roc@roclinux ~]$ find . -name '*.log' -print | xargs rm

借助 xargs,並利用管道的特性,find 命令將輸出的內容分段傳給 rm 命令,而不是一股腦兒地塞過去。這樣一來,rm 命令可以先處理最先獲取的一部分文件,然后再處理下一批,並一直繼續下去,直到全部刪除為止。

好了,xargs 這位護花使者是不是既聰明又聽話呢,在運維過程中,嘗試使用起來吧,你會事半功倍的!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM