“ xargs grep”有什么作用?


25

我知道该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所做的事情而苦苦挣扎,因此我们将不胜感激!


2
这个问题可能会有所帮助:什么时候需要XArgs?
TheOdd

Answers:


30
$ 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则会搞砸,因此请使用null分隔符,并添加-print0xargs -0以获得更可靠的结果:

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

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


2
你可能会考虑提的(因为它似乎你省略)的关键点|管道标准输出到grep的标准输入这是不一样的grep的观点,并给出混乱的结果。

1
或使用GNU find的find -name '*.c' -exec grep stdlib.h {} +。我几乎从来没有真正使用过xargs。还令我惊讶的是,没有人提到xargs在grep $(find)命令替换中起着类似的作用,所以我写了一个答案。将xargs解释为具有较少限制和问题的命令替换似乎很自然。
彼得·科德斯

我使用xargs的一种情况是,由于查找结果我要删除很多文件。如果只执行-exec rm,则它将一次在每个文件上运行rm,这效率很低。用xargs配管将以1 rm一次完成所有操作。用-n50限制(一次执行50个)可以防止命令行溢出(有很多文件的问题)。
lsd

1
@lsd:为什么不find -delete针对这种特殊情况?或者,对于以外的命令rm,如果您有GNU查找,则将它们-exec some_command {} +分组为xargs之类的批处理,而不是将\;每个命令分开运行。
彼得·科德斯

@lsd find在且仅当使用-exec command \;双向时在每个文件上运行命令,xargs并且-exec command \+将使用系统允许的最大参数数量调用该命令。换句话说,它们是等效的
Sergiy Kolodyazhnyy

6

xargs接受其标准输入并将其转换为命令行args。

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,则需要有效地做到这一点。


如果省略xargsfind | grep则其模式是否与要find打印的文件名列表匹配。

因此,此时您也可以这样做find -name stdlib.h。当然,使用时-name '*.c' -name stdlib.h,您将不会获得任何输出,因为这些模式不能同时匹配,并且find的默认行为是将规则与在一起。

less在过程中的任何时候都可以替换以查看管道的任何部分所产生的输出。


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


1
GNU xargs还必须-d设置分隔符,因此您可以使用它-d'\n'来处理以换行符分隔的列表,如果您处理文件中的文件名列表等,这可能会很有用。(只要文件名没有中的换行符。)
ilkkachu 2016年

@ilkkachu:是的,文件名中的换行符比空格少得多,因为它们会破坏大多数脚本。 myfunc(){ local IFS=$'\n'; fgrep stdlib.h` $(find); }也可以达到相同的效果。或者作为单行,(IFS=...; cmd...)子外壳还可以包含对IFS的更改,而无需保存/恢复。
彼得·科德斯

@PeterCordes请不要做任何command $( find )事情。带有空格和特殊字符的有问题的文件名可能会破坏这种情况。至少要用双引号将命令替换。
谢尔盖·科洛迪亚兹尼

@SergiyKolodyazhnyy:感谢您指出我实际上建议这样做。略读的人可能已经复制/粘贴了该内容,而不是阅读下一节。更新以解决该问题。
彼得·科德斯

@SergiyKolodyazhnyy:还是您在回复我的评论?请注意,我设置了IFS它等同于使用xargs '-d\n'。Glob扩展和外壳程序元字符处理发生在命令替换的效果之前,因此即使使用包含$()或的文件名,我也认为这是安全的>。同意在命令替换中使用单词拆分不是一种好习惯,除了一次性交互使用外,您应该对文件名有所了解。但是command "$(find)"仅当您期望它能产生精确的1个文件名时才有用...
Peter Cordes

5

通常,xargs用于将|一个命令中的内容(带有符号)通过管道传递给另一个命令(Command1 | Command2),但未正确接收第一个命令的输出作为第二个命令的输入的情况。

当第二个命令不能正确处理通过Standard In(stdin)输入的数据时,通常会发生这种情况(例如:多行作为输入,行的设置方式,字符用作输入,多个参数作为输入,数据类型接收为输入等)。为了给您一个简单的例子,请测试以下内容:

范例1:

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

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

范例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 echo-在这种情况下,相同的输出find将显示为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')命令可能会失败,因为该$(...)操作的输出将超过外壳程序的最大命令行长度

如其他答案中所述-print0find在这种情况下使用参数to 和-0xargs 参数的原因是,仍可以正确处理带有某些字符(例如,引号,空格甚至换行符)的文件名。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.