
什么是 xargs 命令
xargs命令從標準輸入或另一個命令的輸出中讀取文本行,并將其轉換為命令并執行。
我們經常會看到 xargs 命令與 find 命令一起使用。find 命令提供文件名列表,xargs 命令可以讓我們逐個使用這些文件名,把它們當作是另一個命令的輸入一樣使用。
由于 rargs 會處理重定向,所以你需要提前了解關于標準輸入、輸出以及管道重定向相關的知識。關于管道重定向,可以參考我們之前的文章。
怎樣使用 xargs 命令
xargs 命令的語法如下:
xargs [options] [command [initial-arguments]]
但一般我們不這樣用,它的一個重要功能是將一個命令的輸出組合到另一個命令中。我們看一個例子:
假如在當前路徑下有一些txt文件,以各種鮮花名稱命名,然后還有一個flowers.txt,記錄了所有這些txt文件的名稱:
[gliu@fedora work]$ ls
flowers.txt lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt
[gliu@fedora work]$ cat flowers.txt
lily.txt
one_lotus.txt
rose.txt
three_lotus.txt
two_lotus.txt
現在我們的目標是查看 flowers.txt 中提到的所有文件的文件大小。根據以往的經驗,我們可以使用 cat 命令來顯示所有文件名,然后通過管道將其傳輸到 du 命令來檢查文件大小。
但是如果我們直接使用管道的話,它不會給出 flowers.txt 中提到的每個文件的大小:
[gliu@fedora work]$ du -h
52K.
[gliu@fedora work]$ cat flowers.txt | du -h
52K.
為什么呢?首先,du 命令不接受標準輸入;其次,cat 命令的輸出不是單個的文件名,而是由換行符隔開的一個文本。
而 xargs 命令的神奇之處在于,它將把這個由空格或換行符分割的文本轉換為下一個命令的單獨輸入。
[gliu@fedora work]$ cat flowers.txt | xargs du -h
4.0Klily.txt
4.0Kone_lotus.txt
16Krose.txt
4.0Kthree_lotus.txt
16Ktwo_lotus.txt
這相當于將這些文件名提供給 du 命令:
[gliu@fedora work]$ du -h lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt
4.0Klily.txt
4.0Kone_lotus.txt
16Krose.txt
4.0Kthree_lotus.txt
16Ktwo_lotus.txt
怎么樣,意識到 xargs 命令的強大了嗎?
xargs 和 find:為彼此而存在
xargs 命令經常和 find 命令結合使用。
find 命令搜索文件和目錄并返回它們的名稱,有了 xargs 命令,你就可以將 find 命令的結果用于特定目的,如重命名、移動、刪除等等。
比如,我們要搜索所有包含 red 一詞的txt文件,可以在 xargs 的幫助下結合 find 和
grep 命令:
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs grep -l red
./three_lotus.txt
./two_lotus.txt
./rose.txt
find 與 exec 命令組合的工作原理類似。不過我們今天只集中討論 xargs 命令。
處理文件名中帶有空格的文件
如果文件名中有空格,會稍微麻煩點。比如我們將上面的文件three_lotus.txt重命名為 three lotus.txt,那么當使用 xargs 處理時,會被認為是兩個獨立的文件,three 和 lotus.txt:
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs grep -l red
./two_lotus.txt
grep: ./three: No such file or directory
grep: lotus.txt: No such file or directory
./rose.txt
在這種情況下,可以使用 find 命令的 -print0 選項,它使用 ASCII null 字符來換行,而不是換行符;同時,xargs 命令也需要帶 -0 選項。
[gliu@fedora work]$ find . -type f -print0 -name "*.txt" | xargs -0 grep -l red
./two_lotus.txt
./three lotus.txt
./rose.txt
查看正在執行的命令
xargs 命令的 -t 選項,會打印正在執行的實際命令,所以可以用來查看正在執行的命令。
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs -t touch
touch ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt
在運行命令之前,強制 xargs 提示確認
有些情況需要格外小心,比如刪除文件,最好看看要執行什么命令,必要的話可以選擇拒絕執行。
可以使用 -p 選項,在執行前進行確認:?
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs -p rm
rm ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...n
結合占位符的使用
默認情況下,xargs命令將標準輸入作為參數添加到命令末尾。當需要在最后一個參數之前使用時,這會產生問題。
比如,使用 move 命令,首先需要一個源,然后需要一個目標作為參數;如果要將找到的文件移動的目標文件,那么將不起作用:?
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs -p mv new_dir
mv new_dir ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...y
mv: target './rose.txt' is not a directory
這時候,可以用 -l 選項來使用占位符:?
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs -p -I {} mv {} new_dir
mv ./three_lotus.txt new_dir ?...n
mv ./two_lotus.txt new_dir ?...n
mv ./lily.txt new_dir ?...n
mv ./rose.txt new_dir ?...n
上述命令中,xargs 從 find 命令中獲取所有的文件名,將其保存在 {} 中,然后轉到 mv 命令并提供 {} 中的內容。
這里有一個主要的區別,它不是將所有文件名放在同一個命令中,而是逐個添加。這就是每個參數都會單獨調用 mv 命令的原因。
注:上述命令中使用 {} 作為占位符,你可以使用其他字符作為占位符。{} 是安全的,易于理解和區分。
使用xargs運行多個命令
可以使用 xargs 的占位符來運行多個命令:?
[gliu@fedora work]$ find . -type f -name "*.txt" | xargs -I {} sh -c 'ls -l {}; du -h {}'
-rw-rw-r-- 1 gliu gliu 0 May 28 17:02 ./three_lotus.txt
0./three_lotus.txt
-rw-rw-r-- 1 gliu gliu 0 May 28 17:02 ./two_lotus.txt
0./two_lotus.txt
-rw-rw-r-- 1 gliu gliu 0 May 28 17:02 ./lily.txt
0./lily.txt
-rw-rw-r-- 1 gliu gliu 0 May 28 17:02 ./rose.txt
0./rose.txt
這里需要注意下,占位符不會擴展到下一個管道重定向或者其他命令,這就是上述命令中為什么會使用 sh 命令的原因。
本文主要介紹了常用的 find 和 xargs 命令的使用,但 xargs 命令不是僅限于和find一起用。xargs 命令的一個很實際的例子是當要停止所有正在運行的 docker 容器時:
docker ps -q | xargs docker stop
與其他 Linux 命令一樣,xargs 也有很多選項。關于詳細信息,大家可以查閱 xargs 命令的 man 手冊。