在bash中搜索和写入非常大的文件行

时间:2018-10-17 09:35:38

标签: bash awk cat

我有一个很大的csv文件,其中包含60210行。这些行包含哈希,路径和文件名,如下所示:

hash                 | path     | number | hash-2      | name 
459asde2c6a221f6...  | folder/..| 6      | 1a484efd6.. | file.txt
777abeef659a481f...  | folder/..| 1      | 00ab89e6f.. | anotherfile.txt
....

我正在过滤有关哈希列表的文件,为了简化过滤过程,我创建并使用了该文件的简化版本,如下所示:

hash                 | path     
459asde2c6a221f6...  | folder/..
777abeef659a481f...  | folder/..

过滤后的结果包含所有具有哈希的行,这些哈希在我的参考哈希库中不存在。

但是要对过滤结果进行正确分析,我需要删除之前的数据。因此,我的想法是读取过滤后的结果文件,搜索hash字段,然后将其写入包含所有数据的增强型结果文件中。

我使用循环来做到这一点:

getRealNames() {
    originalcontent="$( cat $originalfile)"
    while IFS='' read -r line; do
        hash=$( echo "$line" | cut -f 1 -d " " )
        originalline=$( echo "$originalcontent"  |grep "$hash" )
        if [ ! -z "$originalline" ]; then
            echo "$originalline" > "$resultenhanced"
        fi
    done < "$resultfile"
}

但是在实际使用中,它的效率非常低:对于以前的文件,此循环大约需要3个小时才能在4Go RAM,Intel Centrino 2系统上运行,对于我来说,这种操作似乎太长了。

有什么办法可以改善此操作?

2 个答案:

答案 0 :(得分:4)

鉴于问题的性质,很难理解为什么在使用awksed之类的专用工具的情况下,您更喜欢使用Shell处理如此大的文件的原因。正如Stéphane ChazelasUnix.SE的精彩回答中所指出的。

使用awk / perl可轻松解决您的问题,这可以加快文本处理速度。另外,您通过执行originalcontent="$( cat $originalfile)"会将整个文件都消耗到RAM中。

假设在原始文件和参考文件中,hash都从第一列开始,并且各列之间用|隔开,那么您需要使用awk作为

awk -v FS="|" 'FNR==NR{ uniqueHash[$1]; next }!($1 in uniqueHash)' ref_file orig_file

以上尝试仅将参考文件中的第一列条目存储到内存中,原始文件完全没有使用。一旦我们使用了参考文件$1(第一列)中的条目,我们就通过选择不在我们创建的数组(uniqueHash)中的那些行来对原始文件进行过滤。

通过将locale的语言环境设置为C

来更改LC_ALL=C awk ...的设置,使其更快。

答案 1 :(得分:-2)

您对要执行的操作的解释不清楚,因为它描述了两个任务:筛选数据,然后将缺失的值添加回筛选的数据。您的示例脚本针对的是第二个脚本,因此我假设这就是您要在此处解决的问题。

在我阅读本文时,您具有包含哈希值和路径的过滤结果,并且需要在原始文件中查找这些哈希值以获取其他字段值。无需将原始文件加载到内存中,只需让 grep 直接处理该文件即可。假设用一个空格(如cut -d " "所示)作为字段分隔符,则也可以在 read 命令中提取散列。

while IFS=' ' read -r hash data; do
    grep "$hash" "$originalfile" >> "$resultenhanced"
done < "$resultfile"