awk - awk 将文件中的字符串与另一个文件匹配并获取前两行和下两行
问题描述
我正在尝试将文件中的字符串与另一个文件进行匹配,以获取匹配的行以及前两行和下两行。
我可以用 grep 来做一个chuck文件,但是会在原始文件上耗尽内存(200M 行的键和一个 2TB 的输入源文件)。
grep --no-group-separator -A 2 -B 1 -f key source
示例密钥文件
^CNACCCAAGGCTCATT
^ANAGCGGCAACTCGCG
我在每一行都添加了“^”,因为关键是在以 '@' 开头的行旁边的起始 16 个字符
图案由长度为 16 的字符 ATGCN 组成,它们是随机的。源文件中可能有多个匹配模式
针对文件的示例搜索
@A00354:427:HVYWLDSXY:1:1101:1036:1000 1:N:0:ATTACTTC
CNACCCAAGGCTCATTCATTATATAGTGGAGGCGGAGAACTTTCCTCCGGTTTGCCTAACATGCCAGCTGTCGGTGTCAAAACCGGCGGATCTCGGGAAGGGGGTCCTGAACTGTGCGTCTTAGGTCGATGGTAATAGGAGACGGGGGAC
+
:#:FFFFFF:F,FFFFFFF:FFF,FF:FFFFFF,FFFFFFFFFFFFFFFF:FFFF:FFFFFFFF:FFFFF,FFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:F,F:FFFFFFFFFFFFFF:F:F,:F:FFFFFFFFFFF:FFF
@A00354:427:HVYWLDSXY:1:1101:1108:1000 1:N:0:ATTACTTC
ANAGCGGCAACTCGCGGTTCCCCTACACATAGAAAACCTACGCCACATTATTGGCTAGGACGAGTGGTTCGTCTGCGTACGCAAGATTGTTGAGATCCACTATTGTCATTCAGTACTACGGTTCTTCTTATCTTGGTCGATCGTGTAAAA
+
F#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFF,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FFFFFFFFFFFFFF
@A00354:427:HVYWLDSXY:1:1101:1271:1000 1:N:0:ATTACTTC
CNATCCCGTCTCGAGCCCGCCCCAATAGCAACAACAACAACAACAACAACAACAACAGCAACAACACCAGCAACACCAGCAACAACAGCAACAACAACAACAGCAACAACAACAACAACAACAACAACAACAACAACAACAACAACAAGA
+
F#FFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFF,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@A00354:427:HVYWLDSXY:1:1101:1325:1000 1:N:0:ATTACTTC
TNCGGTTCATAGGAATGTAGTCTTTGTAATTATGCGCAATTTCCAAACACTTCAAGGTTTTTTTGCAAATAAAACATTCAGGCCTCGTGTGTGCCGCTGCATCTTAGATCCAACGGCTCCTAGTTGCTCATATTCNACCCAAGGCTCATTAGGTGCTCCCCGTAGC
+
:#FFF:F,FFFFFFFFFFFF,:FFF::F,FFF,F:FFFFFFF:FFFF:FF:F:FFF:F:F:FFFFFFFF,FF,F:FF:FF::F,FFF:FFFFFF,:F::FFFFFFF:FF:FFFFF,FFFFFF,FFF:FFFFFFFFF,FFFF:FFFFFFF:
即使我拆分密钥文件,它的速度也很慢。
可以更有效地使用 perl one-liner 或 awk 来完成吗?
预期的输出将是
@A00354:427:HVYWLDSXY:1:1101:1036:1000 1:N:0:ATTACTTC CNACCCAAGGCTCATTCATTATATAGTGGAGGCGGAGAACTTTCCTCCGGTTTGCCTAACATGCCAGCTGTCGGTGTCAAAACCGGCGGATCTCGGGAAGGGGGTCCTGAACTGTGCGTCTTAGGTCGATGGTAATAGGAGACGGGGGAC + :#:FFFFFF:F,FFFFFFF:FFF,FF:FFFFFF,FFFFFFFFFFFFFFFF:FFFF:FFFFFFFF:FFFFF,FFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:F,F:FFFFFFFFFFFFFF:F:F,:F:FFFFFFFFFFF:FFF @A00354:427:HVYWLDSXY:1:1101:1108:1000 1:N:0:ATTACTTC ANAGCGGCAACTCGCGGTTCCCCTACACATAGAAAACCTACGCCACATTATTGGCTAGGACGAGTGGTTCGTCTGCGTACGCAAGATTGTTGAGATCCACTATTGTCATTCAGTACTACGGTTCTTCTTATCTTGGTCGATCGTGTAAAA + F#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
我看到了类似的代码
awk 'NR==FNR{a[$1]; next} {for (i in a) if (index($0, i)) print $1}' key source
它检查 key 中的每个条目是否是源的子字符串,但我无法动脑筋检查模式(^CNACCCAAGGCTCATT)并获取上一个。和下一行
我试过但无法弄清楚的另一种方法是, zcat key | match each line against source file > output
*可能是因为我的代码很慢,非常感谢任何替代品
解决方案
for (i in a) if (index($0, i))
会非常慢,因为您在“搜索”文件的每行循环 100,000,000 次(所以 100M * 2TB 循环迭代!)并且它会产生不正确的输出,因为index($0, i)
会在搜索行的任何位置而不是在开始时找到目标键,它必须index($0, i) == 1
只在开始时匹配。
这是在从“关键”文件行的开头删除所有这些 s 之后在 awk 中执行此操作的方法,^
因为我们将使用字符串进行有效的哈希查找,而不是像 grep 那样进行缓慢的正则表达式比较,并且我们将对每行“源”进行 1 次哈希查找,而不是像您问题中的 awk 脚本中那样进行 100M 字符串比较:
$ cat tst.awk
NR==FNR { tgts[$1]; next }
c && !(--c) { print p3 ORS p2 ORS p1 ORS $0; f=0 }
{ key=substr($0,1,16); p3=p2; p2=p1; p1=$0 }
key in tgts { c=2 }
$ awk -f tst.awk key source
@A00354:427:HVYWLDSXY:1:1101:1036:1000 1:N:0:ATTACTTC
CNACCCAAGGCTCATTCATTATATAGTGGAGGCGGAGAACTTTCCTCCGGTTTGCCTAACATGCCAGCTGTCGGTGTCAAAACCGGCGGATCTCGGGAAGGGGGTCCTGAACTGTGCGTCTTAGGTCGATGGTAATAGGAGACGGGGGAC
+
:#:FFFFFF:F,FFFFFFF:FFF,FF:FFFFFF,FFFFFFFFFFFFFFFF:FFFF:FFFFFFFF:FFFFF,FFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:F,F:FFFFFFFFFFFFFF:F:F,:F:FFFFFFFFFFF:FFF
@A00354:427:HVYWLDSXY:1:1101:1108:1000 1:N:0:ATTACTTC
ANAGCGGCAACTCGCGGTTCCCCTACACATAGAAAACCTACGCCACATTATTGGCTAGGACGAGTGGTTCGTCTGCGTACGCAAGATTGTTGAGATCCACTATTGTCATTCAGTACTACGGTTCTTCTTATCTTGGTCGATCGTGTAAAA
+
F#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFF,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FFFFFFFFFFFFFF
请参阅printing-with-sed-or-awk-a-line-following-a-matching-pattern/17914105#17914105了解更多关于做什么c=2
和c && !(--c)
正在做什么的信息,但它设置了多行的计数,然后变为真(和所以当计数再次达到零时执行打印保存的行的相关操作。
如果这超出了可用内存,请告诉我们,因为另一种方法可能类似于以下伪代码(我不建议您在 shell 中执行此操作!):
sort keys
sort source by middle line keeping groups of 3 lines together
while !done; do
read tgt < keys
while read source_line; do
key = substr(line,1,16)
if key == tgt; then
print line+context
else if key > tgt; then
break
fi
done < source
done
所以这个想法是你不要从“key”读取下一个值,直到“source”的当前值大于你正在使用的值。这会将内存使用量减少到接近于零,但它确实需要对两个输入文件进行排序。
推荐阅读
- python - 你如何从给定的 scipy 随机分布中提取随机数?
- c# - 无法将类型“Microsoft.AspNetCore.Mvc.NotFoundObjectResult”隐式转换为 MyDto
- c# - C# - 基于另一个集合异常过滤集合
- python - tkinter 在一列中返回所有数据库列
- prometheus - Alertmanager 电子邮件通知不起作用
- python - 使用 python SMTP 向 Outlook/Microsoft 发送邮件会出现 SMTPAuthenticationError: Authentication unsuccessful
- next.js - Next.JS 重写没有发生
- c++ - 似乎无法使用数组指针进行第二个 for 循环
- javascript - 根据另一个输入框设置一个输入框的最大值
- java - 无法使用角色 ADMIN spring security 访问 url