我正在尝试对数百个文件的列表运行 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)
格式的临时目录的可怕解决方法,然后从那里 grep 文件。雪莉有更好的方法。
答案1
您似乎正在查找文件名列表,而不是文件本身。<(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
答案2
xargs grep -i -- foo /dev/null < files.txt
假设文件是空白或换行符分隔(其中引号或反斜杠可用于转义这些分隔符)。使用 GNU,xargs
您可以指定分隔符-d
(但随后会禁用引用处理)。
(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))
假设文件以空格、制表符或换行符分隔(尽管您可以通过将其分配给 来选择不同的分隔符,但无法转义这些分隔符IFS
)。如果大多数系统上的文件列表太大,那么该操作将会失败。
这些还假设没有任何文件被称为-
.
答案3
要从标准输入读取文件名列表,您可以使用xargs
.例如,
cat files.txt | xargs -d'\n' grep -i -- 'foo'
默认情况下,xargs
从标准输入读取项目,以空格分隔。告诉-d'\n'
它使用换行符作为参数分隔符,因此它可以处理包含空格的文件名。 (正如 Stéphane Chazelas 指出的,这是一个 GNU 扩展)。但是,它无法处理包含换行符的文件名;我们需要一种稍微复杂的方法来处理这些问题。
FWIW,这种方法比while read
循环要快一些,因为 bash 的read
命令非常慢 - 它逐个字符地读取数据,而xargs
读取输入的效率更高。此外,仅根据需要多次xargs
调用该命令,每次调用都会接收多个文件名,这比为每个文件名单独调用更有效。grep
grep
请参阅xargs 手册页以及 xargs 信息页面以获取更多详细信息。
答案4
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' {}