我有一个通过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
还需要。)