咱們能夠利用管道將一個命令的stdout(標準輸出)重定向到另外一個命令的stdin(標準輸入)。有些命令只能以命令行參數的形式接受數據,而沒法經過stdin接受數據流。這時候就無法使用管道。那麼xargs擅長將標準輸入數據轉換成命令行參數。xargs可以處理stdin並將其轉換爲特定命令的命令行參數。它也能夠將單行或多行文本輸入轉換成其餘格式。html
一、xargs命令應該緊跟在管道操做符以後,以標準輸入做爲主要的源數據流。如command | xargsshell
二、xargs命令把從stdin接受到 的數據從新格式化,再將其做爲參數提供給其餘命令。xargs其做用相似於find命令中的exec。安全
a、將多行輸入轉換成單行輸出。只須要將換行符移除,再用「 」(空格)進行代替,就能夠實現多行輸入的轉換。'\n'被解釋成一個換行符,它其實就是多行文本之間的定界符。bash
eg:$cat example.txt工具
1 2 3 4 5 6編碼
7 8 9 10spa
11 12命令行
$ cat example.txt | xargscode
1 2 3 4 5 6 7 8 9 10 11 12htm
b、將單行輸入轉換成多行輸出。
指定每行最大的參數數量n,能夠將任何來自stdin的文本劃分紅多行,每行n個參數。每一個參數都是由「 」(空格)隔開的字符串。空格是默認的定界符。
eg:$cat example.txt | xargs -n 3
1 2 3
4 5 6
7 8 9
10 11 12
三、工做原理
a、能夠用本身的定界符來分隔參數。用-d選項爲輸入指定一個定製的定界符。
eg:$echo "splitXsplitXsplitXsplit" | xargs - d X
split split split split
b、結合-n選項,能夠將輸入劃分紅多行,而每行包含兩個參數:
eg:$echo "splitXsplitXsplitXsplit" | xargs - d X -n 2
split split
split split
四、補充內容
1)、讀取stdin,將格式化參數傳遞給命令
先編寫一個小型的定製版echo來更好地理解用xargs提供命令行參數的方法:
#!/bin/bash
#文件名:cecho.sh
echo $* '#'
當參數傳遞給文件cecho.sh後,它會將這些參數打印出來,並以#字符做爲結尾。如
$ ./cecho.sh arg1 arg2
arg1 arg2 #
a、有一個名爲args.txt的參數列表文件,以下
$ cat args.txt
arg1
arg2
arg3
能夠將這個命令執行屢次,每次使用一個參數:
$ cat args.txt | xargs -n 1 ./cecho.sh
arg1 #
arg2 #
arg3 #
每次執行須要X個參數的命令時,使用:
INPUT | xargs -n X
如:
$ cat args.txt | xargs -n 2 ./cecho.sh
arg1 arg2 #
arg3 #
爲了在執行命令時一次性提供全部的參數,可使用:
$cat args.txt | xargs ./ cecho.sh
arg1 arg2 arg3 #
上面例子中,直接爲特定的命令(cecho.sh)提供命令行參數。這些參數都源於args.txt文件。但實際上除了以上以外,還須要一些固定不變的命令參數。如
./cecho.sh -p arg1 -1
其中arg1是惟一的可變內容,其他部分都保持不變。咱們能夠從文件(args.txt)中讀取參數,並按照下面的方式提供給命令:
./cecho.sh -p arg1 -1
./cecho.sh -p arg2 -1
./cecho.sh -p arg3 -1
xargs有一個-I選項,能夠提供上面這種形式的命令執行序列。可使用-I指定替換字符串,這個字符串在xarg擴展時會被替換掉。若是將-I與xargs結合使用,對於每個參數,命令都會被執行一次。如
$cat args.txt | xargs -I {} ./cecho.sh -p {} -1
-p arg1 -1 #
-p arg2 -1 #
-p arg3 -1 #
-I {}指定了字符串。對於每個命令參數,字符串{}都會被從stdin讀取到的參數替換掉。
注意:使用-I的時候,命令以循環的方式執行。若是有3個參數,那麼命令就會連同{}一塊兒被執行3次。
2)結合find使用xargs
危險使用:
$find . -type f -name "*.txt" -print | xargs rm -f
這樣作很危險,有可能刪除沒必要要的文件。咱們無法預測分隔find命令輸出結果的定界符到底是什麼('\n'或者' ').有些文件名中包含空格符,所以xargs極可能會誤認爲是定界符(hell text.txt會被xargs誤解爲hell和text.txt)。
只要咱們把find的輸出做爲xargs的輸出做爲xargs的輸入,就必須將-print0與find結合使用,以字符null(‘\0’)來分隔輸出。
用find匹配並列出全部的.txt文件,而後用xargs將這些文件刪除:
$find . -type f -name "*.txt" -print0 |xargs -0 rm -f
這樣就能夠刪除全部的.txt文件。xargs -0 將\0做爲輸入定界符。
3)統計源代碼目錄中全部c程序文件的行數
統計全部c程序文件的行數(Lines of Code,LOC)。
$find source_code_dir_path -type f -name "*.c" -print0 | xargs -0 wc -1
注意:有關我的源代碼更多的統計信息,有個叫作SLOCCount的工具。
d)結合stdin,巧妙運用while語句和子shell
xargs只能以有限的幾種方式來提供參數,並且它也不能爲多組命令提供參數。要執行包含來自標準輸入的多個參數的命令,使用以下:包含while循環的子shell能夠用來讀取參數,而後經過一種巧妙的方式執行命令:
$cat files.txt | (while read arg; do cat $arg;done)
#等同於cat files.txt | xargs -I {} cat {}
在while循環中,能夠將cat $arg替換成任意數量的命令,這樣咱們就能夠對同一個參數執行多條命令。也能夠不借助管道,將輸出傳遞給其餘命令。這個技巧可以適用於各類問題場景。子shell操做符內部的多個命令能夠做爲一個總體來運行。
$cmd0 | (cmd1;cmd2;cmd3) |cmd4
若是cmd1時cd /,那麼就會改變子shell工做目錄,然而這種改變僅侷限於子shell內部。cmd4則徹底不知道工做目錄發生了變化。
轉父Shell與子ShellLogin Shell登陸主機後,在執行Bash Script以前,其實咱們已經處於一個BashShell中。這個Shell叫login Shell,是未來咱們執行任何Script的上層環境。又叫父SHell其實每一個賬號均可以自定義loginShell。以Linux來講,賬號的login Shell定義在/etc/passwd這個文件中。/etc/passwd的每一行表明一個賬號,共有7個字段,之間用:隔開。賬號:x:UID 使用者代碼:GID 羣組代碼:用戶信息:主目錄:login shell路徑第二欄x爲密碼欄,基於系統安全考慮,編碼後的密碼已經被放入/etc/passwd文件中。login Shell定義在第7個字段,若是這個字段的Shell程序不存在、不合法,或執行失敗,則沒法登陸主機。父Shell、子Shell當在執行一個Shell Script時,父Shell會根據Script程序的第一行#!以後指定的Shell程序開啓一個子Shell環境,而後在子Shell中執行此Shell Script。一旦子Shell中的Script執行完畢,此子Shell隨即結束,回到父Shell中,不會影響父Shell本來的環境。子Shell環境擁有與父Shell相同的環境變量、標準輸入、輸出、錯誤等。例如:test.sh文件內容#!/bin/bashcd /var/www/html命令行:chmod +x /test.sh命令行:./test.sh執行完腳本後還原到父Shell,而且父Shell並無進入/var/www/html目錄。注:這是由於當執行Shell文件時,父Shell會建立子Shell,各自獨立。若是須要使用父Shell來執行此腳本,可使用:命令行:. ./test.sh注意.與./之間有一個空格符子Shell繼續開啓子Shell與父Shell啓動子Shell方式同樣,繼續調用下去,即子Shell開啓子Shell。經過$SHLVL變量,能夠知道當前所在Shell的層次