grep但可索引?

时间:2011-10-12 02:23:51

标签: linux grep

我有超过200mb的源代码文件,我必须不断查找(我是一个非常大的团队的一部分)。我注意到grep不会创建索引,因此每次查找都需要遍历整个源代码数据库。

是否有类似于grep的命令行实用程序具有索引功能?

7 个答案:

答案 0 :(得分:9)

以下解决方案相当简单。他们没有涉及很多角落案例:

  • 搜索行的开头^
  • 包含\ n或:的文件名将失败
  • 包含空格的文件名将失败(尽管可以使用GNU Parallel而不是xargs来修复)
  • 搜索与其他文件的路径匹配的字符串将是次优的

解决方案的好处在于它们非常容易实现。

解决方案1:一个大文件

事实:寻求死得很慢,阅读一个大文件往往更快。

鉴于这些事实,我们的想法是简单地创建一个包含所有内容的索引 - 每行包含文件名和行号:

索引目录:

find . -type f -print0 | xargs -0 grep -Han . > .index

使用索引:

grep foo .index

解决方案2:一个大的压缩文件

事实:硬盘很慢。寻求死得很慢。多核CPU是正常的。

因此,读取压缩文件并在运行时解压缩可能比读取未压缩文件更快 - 特别是如果您的RAM足以缓存压缩文件但对于未压缩文件不够。

索引目录:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

使用索引:

pbzcat .index | grep foo

解决方案3:使用索引寻找潜在候选人

生成索引可能非常耗时,您可能不希望为dir中的每个更改执行此操作。

为了加快速度,只需使用索引来识别可能匹配的文件名,并通过那些(希望数量有限的)文件执行实际的grep。这将发现不再匹配的文件,但不会发现匹配的新文件。

需要sort -u以避免多次使用同一文件。

索引目录:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

使用索引:

pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo

解决方案4:附加到索引

重新创建完整索引可能非常慢。如果大多数dir保持不变,您只需使用新更改的文件追加到索引即可。索引将再次仅用于查找潜在候选者,因此如果文件不再匹配,则在浏览实际文件时将发现该文件。

索引目录:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

附加到索引:

find . -type f -newer .index -print0 | xargs -0 grep -Han . | pbzip2 >> .index

使用索引:

pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo

如果您使用pzstd代替pbzip2 / pbzcat,则速度会更快。

解决方案5:使用git

git grep可以通过git存储库进行grep。但它似乎做了很多寻求,并且在我的系统上比解决方案4慢4倍。

好的部分是.git索引小于.index.bz2。

索引目录:

git init
git add .

附加到索引:

git add .

使用索引:

git grep foo

解决方案6:优化git

Git将其数据放入许多小文件中。这导致了寻求。但是你可以让git将小文件压缩成几个更大的文件:

git gc --aggressive

这需要一段时间,但它在几个文件中非常有效地打包索引。

现在你可以做到:

find .git  -type f | xargs cat >/dev/null
git grep foo

git会对索引进行大量搜索,但首先运行cat,将整个索引放入RAM中。

添加到索引与解决方案5中的相同,但是现在运行git gc以避免许多小文件,并且git gc --aggressive在系统空闲时节省更多磁盘空间。 / p> 如果删除文件,

git将不会释放磁盘空间。因此,如果您删除了大量数据,请删除.git并再次执行git init; git add .

答案 1 :(得分:3)

https://code.google.com/p/codesearch/项目能够在索引中创建索引和快速搜索。使用索引支持和计算正则表达式(实际上,只有正则表达式的子集可以使用索引来过滤文件集,然后在匹配的文件上重新评估真正的正则表达式。)

来自codesearch的索引通常是源代码大小的10-20%,构建索引很快就像运行经典grep 2或3次,并且搜索几乎是即时的。

codesearch项目中使用的想法来自谷歌的代码搜索站点(RIP)。例如。索引包含从n-gram(3-gram或源中找到的每个3字节集)到文件的映射;并且在搜索时将正则表达式转换为4克。

PS还有ctags和cscope在C / C ++源代码中导航。 Ctags可以找到声明/定义,cscope更有能力,但是C ++存在问题。

PPS,还有基于铿锵声的C / C ++ / ObjC语言工具:http://blog.wuwon.id.au/2011/10/vim-plugin-for-navigating-c-with.html和clang-complete

答案 2 :(得分:3)

  

我注意到grep不会创建索引,因此每次查找都需要遍历整个源代码数据库。

如果不解决索引能力部分,git grep将会与Git 2.8(2016年第一季度)同时并行运行!

commit 89f09ddcommit 044b1f3commit b6b468bVictor Leschuk (vleschuk)(2015年12月15日)。{
Junio C Hamano -- gitster --于2016年1月12日commit bdd1cc2合并)

  

grep:添加--threads=<num>选项和grep.threads配置

     

git grep”现在可以配置(或从命令行告知)如何   在工作树文件中搜索时要使用的许多线程。

grep.threads:
  

要使用的grep个工作线程数。

答案 3 :(得分:1)

ack是一种代码搜索工具,针对程序员进行了优化,尤其是处理大型异构源代码树的程序员:http://beyondgrep.com/

您的某些搜索示例是否只需要搜索某种类型的文件,例如只搜索Java文件?然后就可以了

ack --java function

ack不会对源代码编制索引,但根据搜索模式的不同,它可能无关紧要。在许多情况下,只搜索某些类型的文件可以提供所需的加速,因为您还没有搜索所有其他XML等文件。

如果ack不为你做,那么这里列出了许多用于搜索源代码的工具:http://beyondgrep.com/more-tools/

答案 4 :(得分:0)

这篇grep-cache文章有一个用于缓存grep结果的脚本。他的例子是在安装了linux工具的Windows上运行的,所以它可以很容易地在nix / mac上使用而几乎没有修改。无论如何,它主要只是一个perl脚本。

此外,文件系统本身(假设您使用* nix)经常缓存最近读取的数据,导致未来的grep时间更快,因为grep有效地搜索virt内存而不是磁盘。

如果要手动删除缓存以查看从未缓存的grep到缓存的grep的速度增加,缓存通常位于/proc/sys/vm/drop_caches

答案 5 :(得分:0)

由于您提到的各种文本文件并非真正的代码,我建议您查看GNU ID utils。例如:

cd /tmp
# create index file named 'ID'
mkid -m /dev/null  -d text /var/log/messages.*
# query index
gid -r 'spamd|kernel'

这些工具专注于令牌,因此无法对令牌字符串进行查询。对于gid命令,emacs中的集成最少。

对于索引源代码的更具体的情况,我更喜欢使用GNU global,我发现它更灵活。例如:

cd sourcedir
# index source tree
gtags .
# look for a definition
global -x main
# look for a reference
global -xr printf
# look for another kind of symbol
global -xs argc

全局本地支持C / C ++和Java,并且通过一些配置,可以扩展为支持更多语言。它还与emacs非常好地集成:连续查询被堆叠,更新源文件可以有效地更新索引。但是我不知道它能够(还)能够对纯文本进行索引。

答案 6 :(得分:0)

我们在内部使用工具来对非常大的日志文件建立索引并对其进行有效搜索。它已经开源。但是,我不知道它可扩展到大量文件的程度。默认情况下,它是多线程的,它在压缩文件内部搜索,并缓存以前搜索的文件的索引。

https://github.com/purestorage/4grep