【问题标题】:Search and write line of a very large file in bash在 bash 中搜索并写入一个非常大的文件的行
【发布时间】:2018-10-17 09:35:38
【问题描述】:

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

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"
}

但在实际使用中,它的效率非常低:对于之前的文件,这个循环在 4Go RAM、Intel Centrino 2 系统上运行大约需要 3 个小时,而且在我看来这种操作的时间太长了。

有什么办法可以改进这个操作吗?

【问题讨论】:

  • 目前还不清楚您给定输入的确切输出是什么。使用确切的详细信息更新问题
  • @Inian 刚刚做到了。我基本上是在过滤有关参考哈希库的行,并且我想获取不在此参考库中的所有哈希的列表。
  • 您能否提供更多输入行进行测试。现在 ref 中的所有行都在原始文件中
  • 60K 行不算大;为什么要减少它?
  • 这是我正在使用的过滤功能的要求。我必须以这种方式格式化输入才能正确过滤。

标签: bash awk cat


【解决方案1】:

鉴于您的问题的性质,很难理解为什么您更喜欢使用 shell 来处理如此庞大的文件,因为专门的工具(如 awksed 来处理它们)。正如Stéphane ChazelasUnix.SE 的精彩回答中指出的那样。

一旦您使用awk/perl 加快文本处理速度,您的问题就会变得很容易解决。此外,您正在通过 originalcontent="$( cat $originalfile)" 将整个文件消耗到 RAM 中,这根本不可取。

假设在原始文件和参考文件中,hash 从第一列开始,各列之间用| 分隔,则需要使用awk as

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

上述尝试仅将参考文件中的第一列条目记入内存,根本不消耗原始文件。一旦我们使用了参考文件的$1(第一列)中的条目,我们就会通过选择不在我们创建的数组(uniqueHash)中的那些行来过滤原始文件。

通过将C 语言环境设置为LC_ALL=C awk ...,更改您的locale 设置以使其更快

【讨论】:

  • 我不太了解awk,但这似乎是解决我的问题的完美解决方案。我会搜索更多关于这些工具的信息,然后再回复您。
【解决方案2】:

您对您要做什么的解释不清楚,因为它描述了两个任务:过滤数据,然后将缺失值添加回过滤后的数据。您的示例脚本解决了第二个问题,所以我假设这就是您要在这里解决的问题。

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

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

【讨论】:

  • 在一个大文件上重复运行grep 是一种糟糕的反模式。
猜你喜欢
  • 2015-03-24
  • 1970-01-01
  • 1970-01-01
  • 2016-05-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-07
  • 2013-01-10
  • 1970-01-01
相关资源
最近更新 更多