【发布时间】:2015-09-03 13:13:02
【问题描述】:
我有一个非常大的文本文件(截至今天为 40 GB),我想过滤出唯一的行而不对文件进行排序。
该文件具有 unix 行结尾,并且所有内容都匹配 [[:print:]]。我尝试了以下 awk 脚本来仅显示唯一行:
awk 'a[$0] {next} 1' stupid.txt > less_stupid.txt
当时的想法是,我会通过引用数组的元素来填充数组,使用文件的内容作为键,然后跳过数组中已经存在的行。但这失败有两个原因 - 首先,因为它莫名其妙地不起作用(即使在小测试文件上),其次因为我知道我的系统会在整个唯一行加载到内存之前耗尽内存通过 awk。
搜索后发现this answer推荐:
awk '!x[$0]++'
虽然这适用于小文件,但在读取我的整个文件之前它也会耗尽内存。
什么是更好的(即有效的)解决方案?我对任何事情都持开放态度,尽管我更偏爱我所知道的语言的解决方案(bash & awk,因此是标签)。在尝试将问题可视化时,我想出的最好方法是存储行校验和或 MD5 数组,而不是行本身,但这只会节省一点空间并存在校验和冲突的风险。
非常欢迎任何提示。告诉我这是不可能的也是受欢迎的,这样我就不再试图弄清楚了。 :-P
【问题讨论】:
-
为什么要避免排序?你需要比排序更快的东西吗?排序后的文件会占用太多空间吗?还是有其他一些因素使排序不可行?
-
如果您无法将完整的唯一行存储在内存中(并且这些行足够短,以至于即使每个行的合理总和(sha256 或其他)也不适合内存)那么我不确定这是否可行。
-
您的原始脚本失败,因为您从未更改
a[$0],这与您找到的答案不同。 -
您说唯一行的集合对于内存来说太大了。重复行的集合是否也太大了?也就是说,如果您排序并找到重复的行,该列表是否适合内存?
-
引用它可能确实会导致它存在 - 作为一个空/零值,它比较 false,因此不会触发下一个子句,等等。替代方法将值从 0 增加到 1第一次,如果值为 0(未初始化)则打印。