使用 awk 解析大文件并提取子集

使用 awk 解析大文件并提取子集

我有一个巨大的文件,如下所示

chr10   98072   1
chr10   98073   1
chr10   98074   1
chr10   98075   2
chr10   98076   2
chr10   98077   3
chr10   98078   5
chr10   98079   5
chr11   98080   5
chr12   98081   5

我对每条染色体都有很多条目。我只想提取包含 chr10 的行。由于我的文件很大,我使用此命令仅提取 chr10 行

awk '$1 ~ /^chr10$/{print}; $1 !~ /^chr10$/{exit}' cov.txt > subset.txt

这是使 awk 不遍历整个文件的好方法吗?我的文件已经在染色体上排序

谢谢

答案1

awk '$1=="chr10"{print; next}{exit}' cov.txt > subset.txt

测试:重定向到/dev/nullfor12,947,909 chr10记录再加上一些chr11chr12总共还有更多99,063,774行 - 输出全部相同(相同的 md5sum)。输出行数 =12,947,909-- 从最快到最慢排序:

史蒂夫:awk '{ if($1 == "chr10") { print } else { exit } }' cov.txt >/dev/null

real  0m5.963s
user  0m5.896s
sys   0m0.064s

彼得·奥:awk '$1=="chr10"{print; next}{exit}' cov.txt >/dev/null

real  0m6.553s
user  0m6.484s
sys   0m0.068s

科斯:perl -pe '!/chr10/&&exit' cov.txt >/dev/null

real  0m8.658s
user  0m8.545s
sys   0m0.112s

史蒂夫:sed -n '/^chr10[^0-9]/ { p; b; }; q' cov.txt >/dev/null

real  0m17.130s
user  0m17.077s
sys   0m0.052s

用户3138373:awk '$1 ~ /^chr10$/{print}; $1 !~ /^chr10$/{exit}' cov.txt >/dev/null

real  0m18.621s
user  0m18.541s
sys   0m0.080s

答案2

试试这个,在我的基本测试中似乎有点快。避免进行正则表达式处理。

[root@localhost tmp]# wc -l cov.txt
34970568 cov.txt
[root@localhost tmp]# time awk '$1 ~ /^chr10$/{print}; $1 !~ /^chr10$/{exit}' cov.txt > subset.txt

real    0m23.897s
user    0m22.031s
sys     0m1.556s
[root@localhost tmp]# time awk '{ if($1 == "chr10") { print } else { exit } }' cov.txt > subset.txt

real    0m16.784s
user    0m14.731s
sys     0m1.661s
[root@localhost tmp]#

也尝试过计时 lcd047 的 sed 方法

[root@localhost tmp]# time sed -n '/^chr10[^0-9]/ { p; b; }; q' cov.txt > subset.txt

real    0m38.343s
user    0m36.609s
sys     0m1.546s
[root@localhost tmp]#

使用普通的旧 grep 是最快的,即使它读取整个文件

[root@localhost tmp]# time grep "^chr10" cov.txt >subset.txt

real    0m6.546s
user    0m4.932s
sys     0m1.577s
[root@localhost tmp]#

本来以为 grep -F 会再次更快,但似乎并非如此。持续超过7秒。

[root@localhost tmp]# time grep -F chr10 cov.txt >subset.txt

real    0m7.317s
user    0m6.109s
sys     0m1.173s
[root@localhost tmp]#

答案3

更有效地,这样做egrep

egrep '^chr10{space or tab}' cov.txt

或者如果内容都与您所显示的类似,

grep -w chr10 cov.txt

答案4

由于文件已排序并且按照你的评论使用 Perl开头的行chr10始终位于文件的开头:

< cov.txt perl -pe '!/chr10/&&exit' > subset.txt

这样,脚本将在第一次出现不匹配时退出。

在内存中存储的 1000000 匹配行文件(通过将chr10 98072 1行附加到空文件 1000000 次获得)上运行的测试立即运行:

~/tmp$ < cov.txt wc -l
1000000
~/tmp$ time < cov.txt perl -pe '!/chr10/&&exit' > subset.txt

real    0m0.631s
user    0m0.624s
sys 0m0.004s
~/tmp$ < subset.txt wc -l
1000000

相关内容