Grep成千上万个文件


13

我的目录包含cca 26 000个文件,我需要在所有这些文件中进行grep。问题是,我需要尽可能快的速度,因此制作grep从find命令获取一个文件的名称并将匹配项写入文件的脚本不是理想的。在出现“参数列表过长”之前,cca花了2分钟时间在所有这些文件中进行grep。有什么想法怎么做?编辑:有一个脚本一直在制作新文件,因此不可能将所有文件放在不同的目录中。


1
findxargsgrep -R
Eddy_Em

它工作正常,但需要10分钟...
user2778979 2013年

Answers:


19

find

cd /the/dir
find . -type f -exec grep pattern {} +

-type f仅用于搜索常规文件(即使符号链接指向常规文件也除外)。如果要搜索除目录以外的任何类型的文件(但请注意,有些类型的文件如fifos或/ dev / zero你一般不想读),更换-type f用GNU特定的! -xtype d-xtype d对于文件类型匹配目录符号链接分辨率后))。

使用GNU grep

grep -r pattern /the/dir

(但是请注意,除非您具有最新版本的GNU grep,否则当进入目录时,它将遵循符号链接)。除非添加-D read选项,否则不会搜索非常规文件。不过,最新版本的GNU grep仍不会在符号链接中搜索。

非常老的GNU版本find不支持标准{} +语法,但是您可以使用非标准语法:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern

性能可能受I / O约束。那是进行搜索的时间,就是从存储中读取所有数据所需的时间。

如果数据位于冗余磁盘阵列上,则一次读取多个文件可能会提高性能(否则可能会使它们降级)。如果性能不受I / O限制(例如,因为所有数据都在缓存中),并且您有多个CPU,那么并发greps也可能会有所帮助。您可以使用GNU xargs-P选项来实现。

例如,如果数据位于具有3个驱动器的RAID1阵列上,或者数据位于高速缓存中,并且您有3个CPU的空闲时间:

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern

(此处-n1000用于grep每1000个文件生成一个新文件,一次最多并行运行3个文件)。

但是请注意,如果grep重定向了的输出,最终将导致来自3个grep进程的交错输出,在这种情况下,您可能希望将其运行为:

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern

(在最新的GNU或FreeBSD系统上)或使用--line-bufferedGNU选项grep

如果pattern为固定字符串,则添加-F选项可以改善问题。

如果不是多字节字符数据,或者对于该模式的匹配,则数据是否为多字节字符都没有关系,则:

cd /the/dir &&
  LC_ALL=C grep -r pattern .

可以显着提高性能。

如果您最终经常进行此类搜索,则可能需要使用众多搜索引擎之一为数据建立索引。


3

对于大多数文件系统,单个目录中的26000个文件很多。可能会花费大部分时间来读取这个大目录。考虑将其拆分为较小的目录,每个目录仅包含数百个文件。

find除非做错了,否则呼叫无法解释性能不佳。这是遍历目录的一种快速方法,并且可以确保您不会冒险尝试执行太长的命令行。确保使用-exec grep PATTERN {} +,每个命令调用可以打包尽可能多的文件,而不要使用-exec grep PATTERN {} \;grep每个文件只能执行一次:每个文件执行一次命令的速度可能会大大降低。


谢谢,我会用谷歌搜索一下,也许我会分开。我正是按照您的意思写的,它花的时间比仅grep的时间长3倍...
user2778979 2013年

Gilles,您是说一个目录中的26,000个文件与分布在100个目录中的26,000个文件的性能会有显着差异吗?
user001

1
@ user001是的。它们的差异取决于文件系统以及可能的基础存储,但是我希望任何文件系统在100个目录中的每个目录中有260个文件,而在单个目录中有26000个文件,其速度要快得多。
吉尔(Gilles)'所以

感谢您的澄清。我就此点提出了一个后续问题,以了解差异的基础。
user001

0

如果您需要多次grep所有文件(如您所说,运行脚本),我建议查看ram磁盘,复制所有文件,然后多次grep文件,这将使您的搜索速度提高一倍至少100倍。

您只需要足够的内存。否则,您应该考虑建立文件索引,例如。进入lucene或nosql数据库,然后在其上运行查询。


如在其他地方所指出的那样,这不利于存在太多文件无法运行的事实grep。还有一点要指出:“有一个脚本一直在制作新文件,因此不可能将所有文件放在不同的目录中。”
杰夫·谢勒

-2

目录中的所有文件

grep 'search string' *

递归地

grep -R 'search string' *

介意-1吗?
马库斯

4
我没有投票,但是您的问题有几个:OP提到了“参数列表太长”,您的第一个列表无法解决,很可能是OP之前所做的。第二个方面在这方面都没有帮助(如果您使用.而不是会有所帮助*)。*将排除点文件(尽管使用-R,但不包括递归目录中的文件)。-R与-r相反,即使在最新版本的GNU grep中也遵循符号链接。您还可以在当前目录中的名称文件的问题开头-
斯特凡Chazelas
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.