为什么 xargs 适用于某些命令,但不适用于其他命令?

为什么 xargs 适用于某些命令,但不适用于其他命令?

我可以运行这个命令并且它有效:

find . -type f -print0 | xargs md5sum

这将打印每个文件的 md5sum。

但对于其他命令,它似乎将所有文件传递给命令的单次调用。例如,printfecho似乎都有这个问题。我printf收到这个警告:

printf: warning: ignoring excess arguments, starting with ...

当使用 echo 时,它只打印一行,例如,如果我有以下命令:

find . -type f -print0 | xargs -r0 echo GOT

我只看到“GOT”打印一次,与找到的所有文件在同一行。

我想也许是因为 echo 也是内置的,但如果我显式运行 /bin/echo ,我会得到相同的行为。

作为参考,我什至在制造命令中遇到了这个问题:

$ echo "a b c" | xargs echo GOT
GOT a b c

代替:

GOT a
GOT b
GOT c

我究竟做错了什么?首先通过在命令前面加上前缀来调试命令对我很有帮助echo,但我什至无法做到这一点。

编辑:正如评论中提到的,我实际上无法使用该-exec选项find,实际上我的管道有点长,其中包含排序,但这似乎是一个无关的细节,与我无法获得的事实无关甚至更简单的管道工作。

答案1

您可以将其视为xargs command-arg运行单个实例的命令,该命令command-arg从标准输入获得的所有内容均附加在其后面,并由某个分隔符(默认为空格或您在示例中使用的 NUL 字节)分隔。例如:

echo 1 2 3 | xargs something

会跑something 1 2 3。或者使用您在问题中发布的示例:

echo "a b c" | xargs echo GOT

运行echo GOT a b c

如果你想使用从标准输入获得的每个参数 xargs 来创建一个新的 command-arg 实例,你可以使用 -n1 选项:

$ echo "a b c" | xargs -n1 echo GOT
GOT a
GOT b
GOT c

当然请注意,某些命令不接受多个参数,因此必须始终使用-n1.

使用 xargs 的优点是生成新进程是一项昂贵的操作,因此使用多个参数运行单个进程会更快,请检查我在这个答案中所做的一些基准测试 https://unix.stackexchange.com/a/536023/72304

答案2

除了-n1第一个答案中提到的“use”之外,您的 shell 可能还有某些命令的内置版本。如果从不同的程序(例如,从 )调用命令xargs,它将调用外部程序而不是 shell 的内置版本。

特别是,printf它内置于 Bash 和其他几个 shell 中,并且 Bash 的内置版本将根据需要多次重复该格式以用完所有参数。

例如,使用 Bash 的内置版本,

printf '%s and %s\n' How now brown cow

将输出 2 行,而

/usr/bin/printf '%s and %s\n' How now brown cow

可能会抱怨它有太多参数,具体取决于您安装的版本。

答案3

通常我会避免xargs

您在网络上找到的大多数示例都很脆弱 - 如果环境与编写代码的人的假设不匹配,它们就会以意想不到的方式崩溃。

即使这个问题中给出的例子也有一个错误:它使用find...-print0但是然后使用xargs 没有 -0

此外,大多数使用xargs都是不必要的。特别是,当它与 结合使用时,在 中find使用表达式既更可靠又不易出错。-execfind

给出的示例可以替换为:

find . -type f -exec md5sum {} +

相关内容