grep 由于内存使用而退出 - 我可以让 grep 不使用那么多内存吗?

grep 由于内存使用而退出 - 我可以让 grep 不使用那么多内存吗?

我有一个通过originallist (dowork.sh Originallist) 进行的操作,并让您知道它在cleaned1 中完成了什么。 clean1 的排序方式与 Originallist 不同。我需要生成供 dowork.sh 处理的剩余内容的列表。本质上是:列表cleanedR - 列表cleaned1 = 列表cleaned2。这是一个负操作。我发现我可以使用以下 grep 选项来执行该操作:

  • F 表示全行匹配而不是正则表达式(我们不希望 grep 对文件名字符感到惊慌,认为它们是正则表达式),
  • v 表示排除(即减号运算),
  • f 查找文件 clean1 中的表达式,而不是单个给定表达式(“从文件获取模式”)。

# wc -l cleaned*
 9157094 cleaned1
 14283591 cleanedR

# du -sh cleaned*
1.3G    cleaned1
2.0G    cleanedR

# grep -Fvf cleaned1 originallist > cleaned2

运行 5 分钟,消耗了 42G 或更少的内存,但很多,然后失败退出; clean2 的长度为 0 字节。

末尾的 clean2 应为 14283591 - 9157094 = 5126497 行长

这是执行此类操作的正确语法(我使用 10 行长的 cleanR 和 3 行长的 clean1 进行了测试;生成的 clean2 为 7 行),但是它消耗了大量的内存。有没有办法让 grep 不消耗那么多内存来完成这项工作?我知道这需要一段时间,但我同意。

我正在寻找类似 sort 的 -T 选项的东西,它允许您不使用 /tmp (在我的例子中是 ram ),并允许您使用另一个目录

sort -h
 -T, --temporary-directory=DIR  use DIR for temporaries, not $TMPDIR or /tmp;
                                multiple options specify multiple directories

答案1

sort 命令对处理大型数据集有一些特定的支持,因为这是一个相对常见的用例。巨大的 grep 模式是一种极其罕见的用例,因此您不能指望开发人员在其中投入大量精力。

如果行的顺序并不重要,您可以对两个文件进行排序,然后可以对它们进行比较,而无需一次在内存中存储多于几行,无论文件有多长。由于排序可以处理内存不足的文件,因此这是高效的。

sort originallist >originallist.sorted
sort cleaned1 | comm -23 originallist.sorted - >cleaned2.sorted

如果 OriginalList 的原始顺序很重要,您可以向其中添加行号:

nl -w 22 originallist >originallist.numbered
# then generate cleaned1 from the numbered list

由于originallist.numbered已排序,您可以comm在其上运行以检测公共行。

如果顺序很重要并且对行进行编号为时已晚,那么您可以尝试分成块并为每个块cleaned1进行一次传递。originallist最近的 GNU 分裂:

cp originalfile cleaned2.in
split -l 1000000 --filter='grep -Fxv -f - cleaned2.in >cleaned2.out; mv cleaned2.out cleaned2.in' cleaned1
mv cleaned2.in cleaned2

(请注意,它F不执行“全行匹配”,而是执行子字符串匹配。对于全行字符串匹配,您-x还需要。)

相关内容