https://www.ruanyifeng.com/blog/2019/08/xargs-tutorial.html
xargs 命令教程 ---同時執行多條命令、多個命令
xargs
是 Unix 系統的一個很有用的命令,但是常常被忽視,很多人不了解它的用法。
本文介紹如何使用這個命令。
一、標准輸入與管道命令
Unix 命令都帶有參數,有些命令可以接受"標准輸入"(stdin)作為參數。
$ cat /etc/passwd | grep root
上面的代碼使用了管道命令(|
)。管道命令的作用,是將左側命令(cat /etc/passwd
)的標准輸出轉換為標准輸入,提供給右側命令(grep root
)作為參數。
因為grep
命令可以接受標准輸入作為參數,所以上面的代碼等同於下面的代碼。
$ grep root /etc/passwd
但是,大多數命令都不接受標准輸入作為參數,只能直接在命令行輸入參數,這導致無法用管道命令傳遞參數。舉例來說,echo
命令就不接受管道傳參。
$ echo "hello world" | echo
上面的代碼不會有輸出。因為管道右側的echo
不接受管道傳來的標准輸入作為參數。
二、xargs 命令的作用
xargs
命令的作用,是將標准輸入轉為命令行參數。
$ echo "hello world" | xargs echo hello world
上面的代碼將管道左側的標准輸入,轉為命令行參數hello world
,傳給第二個echo
命令。
xargs
命令的格式如下。
$ xargs [-options] [command]
真正執行的命令,緊跟在xargs
后面,接受xargs
傳來的參數。
xargs
的作用在於,大多數命令(比如rm
、mkdir
、ls
)與管道一起使用時,都需要xargs
將標准輸入轉為命令行參數。
$ echo "one two three" | xargs mkdir
上面的代碼等同於mkdir one two three
。如果不加xargs
就會報錯,提示mkdir
缺少操作參數。
三、xargs 的單獨使用
xargs
后面的命令默認是echo
。
$ xargs # 等同於 $ xargs echo
大多數時候,xargs
命令都是跟管道一起使用的。但是,它也可以單獨使用。
輸入xargs
按下回車以后,命令行就會等待用戶輸入,作為標准輸入。你可以輸入任意內容,然后按下Ctrl d
,表示輸入結束,這時echo
命令就會把前面的輸入打印出來。
$ xargs hello (Ctrl + d) hello
再看一個例子。
$ xargs find -name "*.txt" ./foo.txt ./hello.txt
上面的例子輸入xargs find -name
以后,命令行會等待用戶輸入所要搜索的文件。用戶輸入"*.txt"
,表示搜索當前目錄下的所有 TXT 文件,然后按下Ctrl d
,表示輸入結束。這時就相當執行find -name *.txt
。
四、-d 參數與分隔符
默認情況下,xargs
將換行符和空格作為分隔符,把標准輸入分解成一個個命令行參數。
$ echo "one two three" | xargs mkdir
上面代碼中,mkdir
會新建三個子目錄,因為xargs
將one two three
分解成三個命令行參數,執行mkdir one two three
。
-d
參數可以更改分隔符。
$ echo -e "a\tb\tc" | xargs -d "\t" echo a b c
上面的命令指定制表符\t
作為分隔符,所以a\tb\tc
就轉換成了三個命令行參數。echo
命令的-e
參數表示解釋轉義字符。
五、-p 參數,-t 參數
使用xargs
命令以后,由於存在轉換參數過程,有時需要確認一下到底執行的是什么命令。
-p
參數打印出要執行的命令,詢問用戶是否要執行。
$ echo 'one two three' | xargs -p touch touch one two three ?...
上面的命令執行以后,會打印出最終要執行的命令,讓用戶確認。用戶輸入y
以后(大小寫皆可),才會真正執行。
-t
參數則是打印出最終要執行的命令,然后直接執行,不需要用戶確認。
$ echo 'one two three' | xargs -t rm rm one two three
六、-0 參數與 find 命令
由於xargs
默認將空格作為分隔符,所以不太適合處理文件名,因為文件名可能包含空格。
find
命令有一個特別的參數-print0
,指定輸出的文件列表以null
分隔。然后,xargs
命令的-0
參數表示用null
當作分隔符。
$ find /path -type f -print0 | xargs -0 rm
上面命令刪除/path
路徑下的所有文件。由於分隔符是null
,所以處理包含空格的文件名,也不會報錯。
還有一個原因,使得xargs
特別適合find
命令。有些命令(比如rm
)一旦參數過多會報錯"參數列表過長",而無法執行,改用xargs
就沒有這個問題,因為它對每個參數執行一次命令。
$ find . -name "*.txt" | xargs grep "abc"
上面命令找出所有 TXT 文件以后,對每個文件搜索一次是否包含字符串abc
。
七、-L 參數
如果標准輸入包含多行,-L
參數指定多少行作為一個命令行參數。
$ xargs find -name "*.txt" "*.md" find: paths must precede expression: `*.md'
上面命令同時將"*.txt"
和*.md
兩行作為命令行參數,傳給find
命令導致報錯。
使用-L
參數,指定每行作為一個命令行參數,就不會報錯。
$ xargs -L 1 find -name "*.txt" ./foo.txt ./hello.txt "*.md" ./README.md
上面命令指定了每一行(-L 1
)作為命令行參數,分別運行一次命令(find -name
)。
下面是另一個例子。
$ echo -e "a\nb\nc" | xargs -L 1 echo a b c
上面代碼指定每行運行一次echo
命令,所以echo
命令執行了三次,輸出了三行。
八、-n 參數
-L
參數雖然解決了多行的問題,但是有時用戶會在同一行輸入多項。
$ xargs find -name "*.txt" "*.md" find: paths must precede expression: `*.md'
上面的命令將同一行的兩項作為命令行參數,導致報錯。
-n
參數指定每次將多少項,作為命令行參數。
$ xargs -n 1 find -name
上面命令指定將每一項(-n 1
)標准輸入作為命令行參數,分別執行一次命令(find -name
)。
下面是另一個例子。
$ echo {0..9} | xargs -n 2 echo 0 1 2 3 4 5 6 7 8 9
上面命令指定,每兩個參數運行一次echo
命令。所以,10個阿拉伯數字運行了五次echo
命令,輸出了五行。
九、-I 參數
如果xargs
要將命令行參數傳給多個命令,可以使用-I
參數。
-I
指定每一項命令行參數的替代字符串。
$ cat foo.txt one two three $ cat foo.txt | xargs -I file sh -c 'echo file; mkdir file' one two three $ ls one two three
上面代碼中,foo.txt
是一個三行的文本文件。我們希望對每一項命令行參數,執行兩個命令(echo
和mkdir
),使用-I file
表示file
是命令行參數的替代字符串。執行命令時,具體的參數會替代掉echo file; mkdir file
里面的兩個file
。
十、--max-procs 參數
xargs
默認只用一個進程執行命令。如果命令要執行多次,必須等上一次執行完,才能執行下一次。
--max-procs
參數指定同時用多少個進程並行執行命令。--max-procs 2
表示同時最多使用兩個進程,--max-procs 0
表示不限制進程數。
$ docker ps -q | xargs -n 1 --max-procs 0 docker kill
上面命令表示,同時關閉盡可能多的 Docker 容器,這樣運行速度會快很多。
十一、參考鏈接
- Linux and Unix xargs command tutorial with examples, George Ornbo
- 8 Practical Examples of Linux Xargs Command for Beginners, Himanshu Arora
(完)
Hank Wang 說:
find . -name *.txt
find 後應該要有路徑?如果我沒加路徑都會報錯。 OSX and Ubuntu.
2019年8月 8日 13:54 | # | 引用
SimonAking 說:
感謝阮老師分享.
2019年8月 8日 14:12 | # | 引用
DeathGhost 說:
假裝學習下...
2019年8月 9日 09:03 | # | 引用
eliefly 說:
之前只知道簡單用下,這次更了解了,感謝。
2019年8月 9日 10:25 | # | 引用
阿木 說:
試了下 -p 參數,發現加上它后命令不會被執行。(Red Hat 4.8.5-16) (GCC) ) #1 SMP Thu Jul 6 19:56:57 EDT 2017 這個系統的。
2019年8月 9日 10:45 | # | 引用
子博 說:
Georgia字體的-0看起來像是-o
2019年8月 9日 11:14 | # | 引用
justyy 說:
windows 下 xargs 的簡單批處理實現 https://helloacm.com/simple-xargs-batch-implementation-for-windows/
2019年8月 9日 23:23 | # | 引用
senninha 說:
批量kill程序,挺實用的。
pgrep EIM | xargs kill -15
2019年8月10日 21:54 | # | 引用
cola6012 說:
xargs倒是沒怎么用過,看過幾次參數,結果很快就忘了
自從同事介紹了 awk | bash的方式,感覺這種方式也挺好用,不需要記參數,想要什么命令自己拼就行了,甭管多復雜的命令都能拼出來,可以先不帶bash,看下拼出來的命令,沒有問題再帶上bash去執行。
2019年8月13日 16:59 | # | 引用
muxueqz 說:
-P的max procs來作多進程並發還挺方便的
2019年8月14日 12:00 | # | 引用
davix 說:
用了這么多年unix tools,沒見過阮老師講這么清楚的。
2019年8月15日 10:41 | # | 引用
zhe 說:
`.` : 當前路徑.
2019年8月22日 11:17 | # | 引用
GodsLeft 說:
推薦一個用法類似的命令,非常好用 parallel,文中最后一個命令可以類似的寫成,私以為比xargs更好用一些
`docker ps -q | parallel -j 10 docker kill {}`
2019年8月23日 10:23 | # | 引用
Sprizy 說:
借此學習一波,把man文檔看一遍
2019年9月 3日 17:12 | # | 引用
Narsil 說:
find . -name "*.txt" | xargs -p grep "abc"
// grep 對於 txt 列表只執行了一次吧?並不是對於一個 txt 執行一次 grep
2020年1月 1日 12:40 | # | 引用
Leith 說:
寫的太好了
2020年3月30日 16:33 | # | 引用
匿名用戶 說:
贊同你的說法,xargs 確實是執行一次。