如何在 Linux 中使用强大的 Xargs 命令 [Explained with Examples]

xargs 是 Linux 中最强大的命令之一。 在本教程中,我将向您展示如何使用 xargs 将标准输入转换为命令。

什么是 xargs 命令?

xargs 命令从标准输入或另一个命令的输出中读取文本行,并将它们转换为命令并执行它们。

您经常会发现 xargs 命令与 find 命令一起使用。 find 命令为您提供文件名列表,xargs 命令让您一个接一个地使用这些文件名,就好像它是另一个命令的输入一样。

由于 xargs 适用于重定向,我强烈建议您复习一下 Linux 中标准输入、标准输出和管道重定向的知识。

如何使用 xargs 命令?

xargs 命令具有以下语法:

xargs [options] [command [initial-arguments]]

但是您可能不会那样使用它。 它的强大之处在于将一个命令的输出组合到另一个命令。 让我们用一个简单的 example.

在我当前的目录中,我有一些文本文件,而 flowers.txt 中有所有这些文件的名称:

[email protected]:~/tutorial$ ls
flowers.txt  lily.txt  one_lotus.txt  rose.txt  three_lotus.txt  two_lotus.txt
[email protected]:~/tutorial$ cat flowers.txt 
lily.txt
one_lotus.txt
rose.txt
three_lotus.txt
two_lotus.txt

现在我的目标是我想查看flowers.txt 中提到的所有文件的文件大小。 常识说我可以结合 cat 命令来显示所有文件名,然后通过管道将其传递给 du 命令以检查文件大小。

但如果我直接通过管道传输,它不会给出flowers.txt 文件中提到的每个文件的大小。

[email protected]:~/tutorial$ du -h
52K	.
[email protected]:~/tutorial$ cat flowers.txt | du -h
52K	.

为什么? 首先,du 命令不接受标准输入。 其次,cat 命令的输出不是单个文件名。 它就像一个由换行符分隔的单词。

xargs 命令的神奇之处在于它将把这个和由空格或新行分隔的文本转换为下一个命令的单独输入。

[email protected]:~/tutorial$ cat flowers.txt | xargs du -h
4.0K	lily.txt
4.0K	one_lotus.txt
16K	rose.txt
4.0K	three_lotus.txt
16K	two_lotus.txt

将其视为等同于将这些文件名提供给 du 命令:

[email protected]:~/tutorial$ du -h lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt 
4.0K	lily.txt
4.0K	one_lotus.txt
16K	rose.txt
4.0K	three_lotus.txt
16K	two_lotus.txt

您现在意识到 xargs 命令的强大功能了,不是吗?

xargs 和 find: 为彼此而生

您会经常发现它与“查找命令”结合使用。 find 命令搜索文件和目录并返回它们的名称。 感谢 xargs,您可以将 find 命令的结果用于特定目的,例如重命名、移动、删除它们等等。

假设您想要获取所有以 .txt 结尾并包含单词 red 的文件。 您可以在 xargs 的帮助下组合 find 和 grep 命令:

[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs grep -l red
./three_lotus.txt
./two_lotus.txt
./rose.txt

处理带空格的文件名

如果您的文件名称中有空格,则会导致问题。 假设我将three_lotus.txt 重命名为“three lotus.txt”。 现在,当它通过 xargs 处理时,它被视为两个单独的文件,如 3 和 lotus.txt。

[email protected]:~/tutorial$ 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 空字符而不是换行符分隔行。 同样,您还应该使用带有 -0 的 xargs 来接受 ASCII 空值。

[email protected]:~/tutorial$ find . -type f -print0 -name "*.txt" | xargs -0 grep -l red
./two_lotus.txt
./three lotus.txt
./rose.txt

查看正在执行的命令

如果你想在 xargs 的帮助下查看正在执行的命令,你可以使用 -t 选项。 它将打印正在执行的实际命令。

[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -t touch
touch ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt

强制 xargs 在运行命令之前提示确认

某些情况需要格外小心,例如删除文件。 查看将要执行的命令并选择拒绝执行将是一个好主意。

您可以使用 xargs 的 -p 选项来获取提示。

[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -p rm
rm ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...n

使用带有 xargs 的占位符来更好地控制它

默认情况下,xargs 命令在命令末尾添加标准输入作为参数。 当您需要在最后一个参数之前使用它时,这会产生问题。

为了 example,如果你使用移动命令,你需要先源,然后是目标。 如果要将找到的文件移动到目标目录,此命令将不起作用:

[email protected]:~/tutorial$ 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

这是您可以在 xargs 中使用带有选项的占位符的地方 – 我喜欢这样:

[email protected]:~/tutorial$ 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 命令的原因(如您在上面看到的 example)。

注意:我使用 {} 作为占位符。 您可以将大多数其他字母或字符作为占位符。 {} 是安全的选择,易于理解和区分。

使用 xargs 运行多个命令

您可以使用占位符通过 xargs 运行多个命令。

[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -I {} sh -c 'ls -l {}; du -h {}' 
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./three_lotus.txt
0	./three_lotus.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./two_lotus.txt
0	./two_lotus.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./lily.txt
0	./lily.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./rose.txt
0	./rose.txt

请记住,占位符不会扩展到下一个管道重定向或其他命令。 这就是我在这里使用 sh 命令的原因。

总是有更多……

我在这里的示例中主要使用 find 和 xargs 命令,因为这是您最常看到的。 但这并不意味着 xargs 仅限于与 find 命令一起使用。 一种这样实用的 example xargs 命令是当您要停止所有正在运行的 docker 容器时:

docker ps -q | xargs docker stop

与大多数其他 Linux 命令一样,xargs 也有更多选项。 您可以随时参考 xargs 命令的手册页 了解更多信息。

我认为这里列出的 xargs 命令示例足以让您很好地理解这个很棒的命令。

如果您有任何问题或建议,请在评论部分告诉我。