列表中的grep文件


14

我正在尝试对几百个文件的列表运行grep:

$ head -n 3 <(cat files.txt)
admin.php
ajax/accept.php
ajax/add_note.php

但是,即使我在文件中找到我知道的字符串时,它们也不会搜索文件:

$ grep -i 'foo' <(cat files.txt)

$ grep -i 'foo' admin.php
The foo was found

我对从文件-f读取模式的标志很熟悉。但是如何读取输入文件

我曾考虑过将文件复制到cp似乎支持该<(cat files.txt)格式的临时目录的可怕方法,然后从那里复制文件。雪莉有更好的方法。

Answers:


22

您似乎在重复文件名列表,而不是文件本身。<(cat files.txt)只是列出文件。尝试<(cat $(cat files.txt))将它们实际连接起来并作为单个流进行搜索,或者

grep -i 'foo' $(cat files.txt)

给grep所有文件。

但是,如果列表中文件太多,则参数数量可能会出现问题。那样的话我就写

while read filename; do grep -Hi 'foo' "$filename"; done < files.txt

谢谢!我没有意识到这样while可以接收file.txt的行。
dotancohen 2015年

您将要在此处禁用该split + glob运算符的glob部分(除非shell是zsh)。
斯特凡Chazelas

1
while没有完全从文件中接收行,read而是这样做了;while只是让我们循环执行此操作。read失败时循环结束(即返回非零返回码),通常是由于到达文件末尾。
下午15年

1
要读取(文本)行,语法为IFS= read -r filename,这read filename是另一回事。
斯特凡Chazelas

1
请注意,这-H是GNU扩展。你想念一些--
斯特凡Chazelas

8
xargs grep -i -- foo /dev/null < files.txt

假设文件为空白或换行符分隔(可以使用引号或反斜杠来转义那些分隔符)。使用GNU,xargs您可以使用来指定定界符-d(尽管如此,然后会禁用引用处理)。

(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))

假设文件之间用空格,制表符或换行符分隔(尽管可以通过将其分配给来选择其他分隔符,但无法逃脱这些分隔符IFS)。如果文件列表在大多数系统上太大,那将失败。

这些还假定没有文件被调用-


最好至少在和中使用$(< file)代替代替。$(cat file)bashzsh
jimmij 2015年

7

要从stdin中读取文件名列表,可以使用xargs。例如,

cat files.txt | xargs -d'\n' grep -i -- 'foo'

默认情况下,xargs从标准输入中读取项目,并以空格分隔。该-d'\n'告诉它使用换行符作为参数分隔符,所以它可以处理包含空格的文件名。(正如StéphaneChazelas指出的,这是GNU扩展)。但是,它不能处理包含换行符的文件名;我们需要一种稍微复杂一些的方法来处理这些问题。

FWIW,这种方法比while read循环要快一些,因为bash的read命令非常慢-它逐字符读取数据,而xargs更有效地读取输入。另外,xargs仅调用grep命令所需的次数,每次调用都会接收多个文件名,这比grep单独调用每个文件名更有效。

有关更多详细信息,请参见xargs手册页和xargs信息页。


3

xargs可以files.txt使用以下选项从文件(如列表)中读取项目:

   --arg-file=file
   -a file
          Read items from file instead of standard input.  If you use this
          option, stdin remains unchanged when commands are  run.   Other
          wise, stdin is redirected from /dev/null.

所以这也应该工作:

xargs -a files.txt grep -i 'foo'

或文件名中的空格

xargs -d'\n' -a files.txt grep -i 'foo'
xargs -I{} -a files.txt grep -i 'foo' {}

1

您也可以进行for,但Orion的示例是最简单的:

for i in $(cat files.txt); do grep -i 'foo' $i ; done

(对于files.txt中列出的每个文件,在其上执行grep命令。)

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.