我正在使用bash在Linux机器上工作。
我的问题是,如何使用grep跳过查询文件中的行?
我正在使用一个名为example.fastq
的〜16Gb大型.fastq文件,其格式如下。
example.fastq
@SRR6750041.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR6750041.2 2/1
CTATANTATTCTATATTTATTCTAGATAAAAGCATTCTATATTTAGCATATGTCTAGCAAAAAAAA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6
@SRR6750041.3 3/1
ATCCANAATGATGTGTTGCTCTGGAGGTACAGAGATAACGTCAGCTGGAATAGTTTCCCCTCACAG
+
AAAAA#EE6E6EEEEEE6EEEEAEEEEEEEEEEE//EAEEEEEAAEAEEEAE/EAEEA6/EEA<E/
@SRR6750041.4 4/1
ACACCNAATGCTCTGGCCTCTCAAGCACGTGGATTATGCCAGAGAGGCCAGAGCATTCTTCGTACA
+
/AAAA#EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEAE/E/<//AEA/EA//E//
@SRR6750041.5 5/1
CAGCANTTCTCGCTCACCAACTCCAAAGCAAAAGAAGAAGAAAAAGAAGAAAGATAGAGTACGCAG
+
AAAAA#EEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEEEEE/EEEAEEEAEEE<EE/E
我需要提取包含感兴趣的字符串@SRR6750041.2
@SRR6750041.5
的行,该行存储在名为IDarray
的bash数组中,以及每次匹配后的3行。以下grep命令允许我执行此操作
for ID in "${IDarray[@]}";
do
grep -F -A 3 "$ID " example.fastq
done
这将正确输出以下内容。
@SRR6750041.2 2/1
CTATANTATTCTATATTTATTCTAGATAAAAGCATTCTATATTTAGCATATGTCTAGCAAAAAAAA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6
@SRR6750041.5 5/1
CAGCANTTCTCGCTCACCAACTCCAAAGCAAAAGAAGAAGAAAAAGAAGAAAGATAGAGTACGCAG
+
AAAAA#EEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEEEEE/EEEAEEEAEEE<EE/E
我正在寻找加快此过程的方法...一种方法是通过将搜索限制为以@开头的行或跳过可能不包含匹配{{的行,以减少grep搜索的行数。 1}},例如第2、3、4和6、7、8行等。有没有办法使用grep做到这一点?也欢迎使用其他方法!
答案 0 :(得分:1)
以下是一些带有示例的想法。出于测试目的,我创建了一个测试用例,例如您的example_mini.fastq的迷你版,其大小为145 MB,IDarray具有999个元素(兴趣)。
您的版本具有这种性能(在用户空间中超过2分钟):
$ time for i in "${arr[@]}"; do grep -A 3 "${i}" example_mini.fastq; done 1> out.txt
real 3m16.310s
user 2m9.645s
sys 0m53.092s
$ md5sum out.txt
8f199a78465f561fff3cbe98ab792262 out.txt
第一次匹配-m 1
之后,第一次将grep升级到结束grep,我假设兴趣ID是唯一的。这样可以减少50%的复杂度,并在用户空间中花费大约1分钟的时间:
$ time for i in "${arr[@]}"; do grep -m 1 -A 3 "${i}" example_mini.fastq; done 1> out.txt
real 1m19.325s
user 0m55.844s
sys 0m21.260s
$ md5sum out.txt
8f199a78465f561fff3cbe98ab792262 out.txt
这些解决方案线性依赖于元素数量。在大文件上调用n次grep。
现在让我们仅在AWK中实现一次运行,我将IDarray导出到输入文件中,因此可以一次运行。我将每个ID的大文件加载到关联数组中,然后通过您的ID数组循环搜索1次。这是一般情况,您可以定义正则表达式和打印后的行数。仅通过一次文件+ N次比较就具有复杂性。这提高了2000%:
$ for i in "${arr[@]}"; do echo $i; done > IDarray.txt
$ time awk '
(FNR==NR) && (linesafter-- > 0) { arr[interest]=arr[interest] RS $0; next; }
(FNR==NR) && /^@/ { interest=$1; arr[interest]=$0; linesafter=3; next; }
(FNR!=NR) && arr[$1] { print(arr[$1]); }
' example_mini.fastq IDarray.txt 1> out.txt
real 0m7.044s
user 0m6.628s
sys 0m0.307s
$ md5sum out.txt
8f199a78465f561fff3cbe98ab792262 out.txt
与标题中的一样如果您真的可以确认是否有第四行是感兴趣的ID,则将在其后打印三行。您可以将其简化并再提高20%:
$ for i in "${arr[@]}"; do echo $i; done > IDarray.txt
$ time awk '
(FNR==NR) && (FNR%4==1) { interest=$1; arr[interest]=$0; next; }
(FNR==NR) { arr[interest]=arr[interest] RS $0; next; }
(FNR!=NR) && arr[$1] { print(arr[$1]); }
' example_mini.fastq IDarray.txt 1> out.txt
real 0m5.944s
user 0m5.593s
sys 0m0.242s
$ md5sum out.txt
8f199a78465f561fff3cbe98ab792262 out.txt
在具有999个元素的1.5 GB文件上,搜索时间为:
real 1m4.333s
user 0m59.491s
sys 0m3.460s
因此,根据我对计算机的预测,您的15 GB示例包含10k元素将需要大约16分钟的用户空间来处理。