12
grep -F -f file1  file2

file1 为 90 Mb(250 万行,每行一个字)

文件 2 为 45 Gb

无论我让它运行多长时间,该命令实际上都不会产生任何东西。显然,这超出了 grep 的范围。

似乎 grep 无法处理来自该-f选项的那么多查询。但是,以下命令确实会产生所需的结果:

head file1  >  file3
grep -F -f file3   file2

考虑到文件大小,我怀疑 sed 或 awk 是否是合适的替代品。

我不知所措……请帮忙。sql学习一些命令值得吗?这简单吗?谁能指出我正确的方向?

4

4 回答 4

17

尝试使用 LC_ALL=C 。它将搜索模式从 UTF-8 转换为 ASCII,其速度是原始速度的 140 倍。我有一个 26G 的文件,我需要大约 12 个小时才能完成几分钟。资料来源:Grepping一个巨大的文件(80GB)有什么办法可以加快速度?

所以我要做的是:

LC_ALL=C fgrep "pattern" <input >output
于 2013-11-05T01:32:15.967 回答
5

我不认为有一个简单的解决方案。

想象一下,您编写了自己的程序来执行您想要的操作,并且最终会得到一个嵌套循环,其中外部循环遍历 file2 中的行,而内部循环遍历 file1(反之亦然)。迭代次数随 增加size(file1) * size(file2)。当两个文件都很大时,这将是一个非常大的数字。使用缩小一个文件head显然可以解决这个问题,但代价是不再给出正确的结果。

一种可能的出路是索引(或排序)其中一个文件。如果您遍历 file2 并且对于每个单词,您可以确定它是否在模式文件中,而无需完全遍历模式文件,那么您的情况会好得多。这假设您进行逐字比较。如果模式文件不仅包含完整的单词,还包含子字符串,那么这将不起作用,因为对于 file2 中的给定单词,您将不知道在 file1 中查找什么。

学习 SQL 肯定是个好主意,因为学习一些东西总是好的。它会悬停,不能解决您的问题,因为 SQL 将遭受上述相同的二次效应。如果索引适用于您的问题,它可能会简化索引。

你最好的选择可能是退后一步,重新思考你的问题。

于 2013-05-03T02:46:01.760 回答
4

你可以试试ack。他们说它比 grep 快。

您可以尝试并行

parallel --progress -a file1 'grep -F {} file2'

Parallel 还有许多其他有用的开关来加快计算速度。

于 2013-05-03T05:51:19.280 回答
2

Grep 无法处理那么多查询,而且在那个量下,修复使它如此缓慢的grep -f错误也无济于事。

file1 和 file2 是否都由每行一个单词组成?这意味着您正在寻找完全匹配的内容,我们可以通过以下方式快速完成awk

awk 'NR == FNR { query[$0] = 1; next } query[$0]' file1 file2

NR(记录数,行号)仅等于第一个文件的 FNR(文件特定记录数),我们在其中填充哈希,然后移至下一行。第二个子句检查其他文件的行是否与保存在我们哈希中的行匹配,然后打印匹配的行。

否则,您将需要迭代:

awk 'NR == FNR { query[$0]=1; next }
     { for (q in query) if (index($0, q)) { print; next } }' file1 file2

我们不仅要检查散列,还必须遍历每个查询,看看它是否与当前行匹配($0)。这慢得多,但不幸的是这是必要的(尽管我们至少在不使用正则表达式的情况下匹配纯字符串,所以它可能会更慢)。当我们有匹配时,循环停止。

如果您真的想将查询文件的行作为正则表达式进行评估,您可以使用$0 ~ q更快的index($0, q). 请注意,这使用了POSIX 扩展的正则表达式,与或没有有界量词( ) 或单词边界的GNU 扩展( ) 和速记字符类( ,等)大致相同grep -Eegrep没有。{1,7}\b\s\w

只要哈希不超过awk可以存储的内容,这些应该可以工作。这可能低至 2.1B 条目(基于最高 32 位有符号整数的猜测)或与您的可用内存一样高。

于 2016-07-15T01:08:44.263 回答