在几千个文件中使用 Grep

use*_*979 15 performance grep files

我有包含 cca 26 000 个文件的目录,我需要在所有这些文件中使用 grep。问题是,我需要尽可能快地使用它,因此制作脚本并不理想,其中 grep 将从 find 命令中获取一个文件的名称并将匹配项写入文件。在“参数列表太长”问题之前,在所有这些文件中 grep 花了 cca 2 分钟。任何想法如何做到这一点?编辑:有一个脚本一直在创建新文件,因此不可能将所有文件放在不同的目录中。

Sté*_*las 21

find

cd /the/dir
find . -type f -exec grep pattern {} +
Run Code Online (Sandbox Code Playgroud)

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

使用 GNU grep

grep -r pattern /the/dir
Run Code Online (Sandbox Code Playgroud)

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

很旧版本的 GNUfind不支持标准{} +语法,但您可以使用非标准语法:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern
Run Code Online (Sandbox Code Playgroud)

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

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

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

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern
Run Code Online (Sandbox Code Playgroud)

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

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

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern
Run Code Online (Sandbox Code Playgroud)

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

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

如果不是多字节字符数据,或者如果为了匹配那个模式,不管数据是不是多字节字符,那么:

cd /the/dir &&
  LC_ALL=C grep -r pattern .
Run Code Online (Sandbox Code Playgroud)

可以显着提高性能。

如果您最终经常进行此类搜索,那么您可能希望使用众多搜索引擎之一为您的数据编制索引。