“xargs grep” 起什么作用?

“xargs grep” 起什么作用?

我知道该grep命令,并且正在学习其功能xargs,因此我通读了该页面提供了一些如何使用该xargs命令的示例。

最后一个例子,即示例 10,让我感到困惑。它说“xargs 命令执行 grep 命令来查找所有包含字符串‘stdlib.h’的文件(在 find 命令提供的文件中)”

$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...

但是,与简单地使用

$ find . -name '*.c' | grep 'stdlib.h'

显然,我仍然在努力弄清楚 xargs 到底在做什么,因此非常感谢您的帮助!

答案1

$ find . -name '*.c' | grep 'stdlib.h'

这将输出 (stdout)* 从 管道传输find到 (stdin of)*grep 'stdlib.h' 作为文本(即文件名被视为文本)。grep执行其常规操作并在此文本中找到匹配的行(任何本身包含模式的文件名)。文件的内容永远不会被读取。

$ find . -name '*.c' | xargs grep 'stdlib.h'

这构造了一个命令 grep 'stdlib.h'每个结果find都是一个参数 - 因此这将寻找匹配项里面find(xargs可以被认为是将其 stdin 转换为给定命令的参数)*找到的每个文件

-type f在 find 命令中使用,否则您将收到grep匹配目录的错误。此外,如果文件名中有空格,xargs将严重出错,因此请使用空分隔符,通过添加-print0xargs -0来获得更可靠的结果:

find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

*根据@cat的评论建议添加了这些额外的解释点

答案2

xargs 获取其标准输入并将其转换为命令行参数。

find . -name '*.c' | xargs grep 'stdlib.h'非常类似于

grep 'stdlib.h' $(find . -name '*.c')  # UNSAFE, DON'T USE

只要文件名列表对于单个命令行来说不是太长,就会产生相同的结果。(Linux 在单个命令行上支持兆字节的文本,因此通常不需要 xargs。)


但这两者都很糟糕,因为如果文件名包含空格,则会中断。相反,find -print0 | xargs -0有效,但

find . -name '*.c' -exec grep 'stdlib.h' {} +

它永远不会将文件名通过管道传输到任何地方:find将它们分批放入一个大的命令行中并grep直接运行。

\;而不是+对每个文件分别运行 grep,这样会慢得多。不要这样做。但是这+是 GNU 扩展,因此xargs如果您不能假设 GNU find,则需要有效地执行此操作。


如果省略xargsfind | grep则根据打印的文件名列表进行模式匹配find

因此,此时您不妨直接执行find -name stdlib.h。当然,使用-name '*.c' -name stdlib.h,您将不会获得任何输出,因为这些模式不能同时匹配,而 find 的默认行为是将规则进行 AND 运算。

less在流程中的任意一点进行替换,查看管道的任何部分产生的输出。


进一步阅读:http://mywiki.wooledge.org/BashFAQ有一些很棒的东西。

答案3

一般来说,xargs用于以下情况:您想将|某个内容(使用符号 )从一个命令传输到另一个命令(Command1 | Command2),但第一个命令的输出不能正确地作为第二个命令的输入。

这通常发生在第二条命令无法正确处理通过标准输入 (stdin) 输入的数据时(例如:多行作为输入、行设置方式、用作输入的字符、多个参数作为输入、作为输入接收的数据类型等)。举一个简单的例子,测试以下内容:

示例 1:

ls | echo- 这不会做任何事情,因为echo不知道如何处理他收到的输入。现在在这种情况下,如果我们使用xargs它,它将以可以正确处理的方式处理输入echo(例如:作为单行信息)

ls | xargs echols- 这将在一行中输出所有信息

示例 2:

假设我在一个名为 go 的文件夹中有多个 goLang 文件。我会用这样的方法查找它们:

find go -name *.go -type f | echo- 但是如果管道符号在那里并且echo位于末尾,它将不起作用。

find go -name *.go -type f | xargs echo- 在这里它可以工作,xargs但如果我想要find命令的每个响应都在一行中,我会执行以下操作:

find go -name *.go -type f | xargs -0 echofind- 在这种情况下,将显示相同的输出echo

诸如 和其他需要更好方式处理输入的命令cp, echo, rm, less与 一起使用时会受益xargs

答案4

xargs用于(通常)根据文件列表自动生成命令行参数。

因此,考虑使用以下xargs命令的一些替代方法:

find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

有几个理由使用它来代替其他答案中最初未提及的其他选项:

  1. find . -name '*.c' -exec grep 'stdlib.h' {}\;将为每个文件生成一个grep进程——这通常被认为是不好的做法,并且如果找到许多文件,可能会给系统带来很大的负载。
  2. 如果文件很多,grep 'stdlib.h' $(find . -name '*.c')命令很可能会失败,因为操作的输出$(...)将超出 shell 的最大命令行长度

正如其他答案中提到的,在这种情况下使用-print0参数和 xargs 参数的原因是,带有某些字符(例如引号、空格甚至换行符)的文件名仍然能被正确处理。find-0

相关内容