条件分割HUGE文件

时间:2017-11-24 15:23:20

标签: bash split

我有一个非常庞大的文件(> 5亿行),我希望根据其中一列的前3个字符拆分成几个较小的文件。

看起来像这样,第1列和第2列的每个元素都是唯一的:

A0A023GPI8  A0A023GPI8.1    232300  1027923628
A0A023GPJ0  A0A023GPJ0.2    716541  765680613
A0A023PXA5  A0A023PXA5.1    559292  728048729
A0A023PXB0  A0A023PXB0.1    559292  728048786
A0A023PXB5  A0A023PXB5.1    559292  728048524
A0A023PXB9  A0A023PXB9.1    559292  728048769
A0A023PXC2  A0A023PXC2.1    559292  728050382

我使用下面的脚本认为它会很快,因为在我看来它只涉及整个文件的单个读取。然而,它已经运行了几天而且还远未完成。有什么想法可以解释为什么,提出解决方案吗?

while read line
do
    PREFIX=$(echo "$line" | cut -f2 | cut -c1-3)
    echo -e "$line" >> ../split_DB/$PREFIX.part
done < $file

2 个答案:

答案 0 :(得分:3)

read效率不高;它必须一次读取一个字符以避免读取下一个换行符。但是,这里有很大的开销来源是每行调用cut两次。我们可以通过再次使用read进行拆分,并使用参数扩展来提取第二列的第一个字符来避免这种情况。

while read -r line; do
    read -r _ col2 _ <<< "$line"
    prefix=${col2:0:3}
    # If the first column has a fixed width, you can forgo the
    # previous two lines and use
    #   prefix=${line:12:3}
    printf '%s\n' "$line" >> ../split_DB/$prefix.part
done < "$file"

但是,我不会花费太多时间在bash中有效地执行此操作:这是一个快速而肮脏的Python脚本,它将执行相同的操作:

output_files = {}
with open(file) as fh:
    for line in fh:
        cols = line.strip().split()
        prefix = cols[1][0:3]
        # Cache the output file handles, so that each
        # is opened only once.
        outfh = output_files.setdefault(prefix, open("../split_DB/{}.part".format(prefix), "w"))
        print(line, file=outfh)
    # Close all the output files
    for f in output_files.values():
        f.close()

答案 1 :(得分:3)

这很容易:

$ awk '{s=substr($2,1,3); print >> s}' file

>>重定向打印以按给定的名称附加文件。名称由第二列的前3个字母组成。

这将比Bash处理此文件更快。

注意:

通常,操作系统对打开的同时文件数量有限制。根据第二列的前3个字符中潜在字符组合的数量,此可能成为问题。这将影响任何解决方案,其中这些名称的文件在处理给定文件时保持打开 - 而不仅仅是awk。

如果您有000999,则可能会打开999个潜在文件;如果你有AAAZZZ即17,575;如果您有三个带大写和小写的字母数字,那就是238,327 potential 打开文件...如果您的数据只有几个唯一的前缀,您可能不需要担心这个;如果您说明数据的详细信息,则此处建议的解决方案可能会有所不同。

(您可以根据3个字符中允许的字母长度计算基本转换为'ZZZ'的潜在组合为小数。('0'..'9','A'..'Z')基数为32 ('0'..'9','a'..'z','A'..'Z')为基数62等等。)

如果需要(在合理范围内)或者根据需要打开和关闭新文件,您可以使用大多数Unix风格的操作系统提高限制。将文件限制提高到238,327是不切实际的。您还可以对数据进行排序,并在不使用时关闭以前的文件。