管道时何时使用 xargs?

When to use xargs when piping?

我是 bash 的新手,我正在尝试了解 xargs 的用法,这对我来说仍然不是很清楚。例如:

history | grep ls

这里我在我的历史记录中搜索命令ls。在此命令中,我没有使用 xargs,它运行良好。

find /etc - name "*.txt" | xargs ls -l

我这个,我不得不使用 xargs 但我仍然无法理解其中的区别,我无法正确决定何时使用 xargs 以及何时不使用。

xargs(1) 在 读取非 NUL 分隔输入.

时是危险的(已损坏、可利用等)

如果您使用的是文件名,请改用 find 的 -exec [command] {} +。 如果您可以获得以 NUL 分隔的输出,请使用 xargs -0.

简短回答:暂时避免xargs。 Return 到 xargs 当您编写了数十个或数百个脚本时。

命令可以从参数中获取输入(比如rm bad_example)或者可以从stdin中获取输入(不仅是rm -i is_this_bad_too之后的y,还有read answer).其他命令如 grepsed 将查找参数,当参数不显示输入时,切换到输入。
您的 grep 示例可以很好地从标准输入读取,不需要什么特别的东西。
您的 ls 需要 find 的输出作为参数。 xargs 只是扭转局面的一种方式。使用 man xargs 了解更多关于 xargs 的信息。备选方案:

find /etc -name "*.txt" -exec ls -l {} \;
find /etc -name "*.txt" -ls
ls -l $(find /etc -name "*.txt" )
ls /etc/*.txt

当你在 /etc 中有 a nasty filename with spaces.txt 时,首先尝试看看哪个命令是最好的。

GNU Parallel 可以做与 xargs 相同的事情,但没有损坏和可利用的 "features"。

您可以通过查看示例来学习 GNU Parallel http://www.gnu.org/software/parallel/man.html#EXAMPLE:-Working-as-xargs--n1.-Argument-appending and walking through the tutorial http://www.gnu.org/software/parallel/parallel_tutorial.html

xargs 可以在需要从一个命令获取输出并将其用作另一个命令的参数时使用。在您的第一个示例中, grep 从标准输入中获取数据,而不是作为参数。所以,不需要xargs

xargs 从标准输入中获取数据并执行命令。默认情况下,数据作为参数附加到命令的末尾。但是,它可以插入任何地方,使用占位符作为输入。传统的占位符是{};使用它,您的示例命令可能会写成:

find /etc -name "*.txt" | xargs -I {} ls -l {}

如果 /etc 中有 3 个文本文件,您将获得每个文件的完整目录列表。当然,你可以直接写 ls -l /etc/*.txt 省去麻烦。

另一个示例让您重命名这些文件,并要求占位符 {} 使用两次。

find /etc -name "*.txt" | xargs -I {} mv {} {}.bak

这些都是不好的例子,一旦你有一个包含空格的文件名就会崩溃。您可以通过告诉 find 用空字符分隔文件名来解决这个问题。

find /etc -print0 -name "*.txt" | xargs -I {} -0 mv {} {}.bak

我个人的看法是,几乎总有使用 xargs 的替代方法(例如 find-exec 参数),学习这些方法会更好。

当您使用不带 xargs 的管道时,实际数据将输入到下一个命令中。另一方面,当使用带有 xargs 的管道时,实际数据被视为下一个命令的参数。举一个具体的例子,假设您有一个包含 a.txtb.txt 的文件夹。 a.txt 只包含一行 'hello world!',而 b.txt 只是空行。

如果你这样做

ls | grep txt

你最终会得到输出:

a.txt
b.txt

然而,如果你这样做

ls | xargs grep txt

你什么也得不到,因为文件 a.txt 和 b.txt 都不包含单词 txt.

如果命令是

ls | xargs grep hello

你会得到:

hello world!

那是因为 xargsls 给出的两个文件名作为参数传递给 grep,而不是实际内容。