按样本标识符排序文本文件的最快方法

时间:2017-03-20 02:29:15

标签: bash sorting awk sed bisection

我需要对文件进行排序, mwe.txt

>gb|LOEQ01000001.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000181.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
>gb|LOEQ01000131.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
3   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1

names.txt 中的示例标识符:

LOEQ01000001.1
LOEQ01000131.1
LOEQ01000181.1

我已经用sed和awk实现了这个目标:

for f in $(cat names.txt); do sed -n -e "/$f|/,/>/ p" mwe.txt | awk '/>/&&c++>0 {next} 1' >> sorted.txt; done

结果是:

>gb|LOEQ01000001.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000131.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
3   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000181.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1

我使用的实际文件大于120gb,我的解决方案效率非常低。我想可以使用递归合并排序算法,但我不确定如何组织输入数据以便对其进行排序,主要是因为每个样本/标识符的行数不一致。任何人都可以建议更快的方式吗?

1 个答案:

答案 0 :(得分:4)

$ cat tst.awk
BEGIN { FS="|" }
NR==FNR { keys[++numKeys] = $0; next }
/^>/ { key = $2 }
{ block[key] = block[key] $0 ORS }
END {
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s", block[key]
    }
}

$ awk -f tst.awk names.txt mwe.txt
>gb|LOEQ01000001.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000131.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
3   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000181.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1

这会更快,但它确实意味着你需要将整个文件存储在内存中,所以试试看看是否存在问题。如果是,那么您可以一次获取一些键名称,并使用类似这样的脚本:

$ cat tst.awk
BEGIN { FS="|" }
NR==FNR { keys[++numKeys] = $0; tgtKeys[$0]; next }
/^>/ { key = $2 }
key in tgtKeys { block[key] = block[key] $0 ORS }
END {
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s", block[key]
    }
}

< names.txt xargs -n 1000 echo | awk -f tst.awk - mwe.txt

将一次打印mwe.txt 1000行。