如何提取匹配指定ID的Hit行及对应Query行?
解决方案:用Awk一次性关联Query与匹配的Hit记录
首先,你的核心需求是:保留File.txt中的Query记录,同时只保留那些Hit记录里包含ID.txt中指定ID的条目,并且保证Query和对应的Hit正确关联。你之前用循环调用Awk的方式存在几个关键问题:
- 每次循环都会覆盖
output.txt,最后只会留下最后一个ID的匹配结果 - Awk单引号内的
"$i"无法正确传递shell变量,因为单引号会屏蔽shell变量解析 - 没有维护Query和Hit的关联关系,容易出现重复输出Query或丢失对应关系的情况
完全不需要shell循环,用Awk就能一次性完成所有操作,效率更高也更准确。
正确的Awk命令
awk ' BEGIN { # 先读取ID.txt里的所有ID,存入数组id_map,实现快速查找 while (getline < "ID.txt") { id_map[$0] = 1 } close("ID.txt") current_query = "" query_printed = 0 } # 遇到Query行时,记录当前Query,并标记该Query未输出 /^Query:/ { current_query = $0 query_printed = 0 next } # 处理Hit行:检查Hit后的第一个字段是否在指定ID集合中 /^Hit:/ { hit_id = $2 if (id_map[hit_id]) { # 如果当前Query还未输出,先打印Query if (!query_printed) { print current_query query_printed = 1 } # 打印匹配的Hit行 print $0 } } ' File.txt > output.txt
命令细节解释
- BEGIN块:在处理目标文件File.txt之前,先读取ID.txt的所有内容,将每个ID作为数组
id_map的键存储,这样后续判断ID是否存在的操作是O(1)级别的,非常高效。 - Query行处理:每当匹配到
Query:开头的行,就将该行内容存入current_query变量,同时把query_printed标记为0(表示这个Query还未被输出过)。 - Hit行处理:匹配到
Hit:开头的行时,提取Hit后的第一个字段(即$2,比如AMP2_FAGES),检查它是否在id_map中。如果存在:- 若当前Query还未输出,先打印该Query
- 接着打印当前的Hit行
- 最终结果重定向到
output.txt,不会像循环方式那样反复覆盖文件内容。
验证结果
用你提供的测试数据运行该命令后,output.txt的内容会和你期望的完全一致:
Query: PROKKA_00022 hypothetical protein - 36 aa
Hit: AMP2_FAGES UniProt Fag e 4 UniProt P0DKH8 http://www.u 100.0% identity
Hit: Q6JYQ7_HEVBR UniProt Hev b 6 UniProt Q6JYQ7 http://www 100.0% identity
Query: PROKKA_00572 hypothetical protein - 36 aa
Hit: AMP2_FAGES UniProt Fag e 4 UniProt P0DKH8 http://www.u 100.0% identity
Hit: Q6JYQ7_HEVBR UniProt Hev b 6 UniProt Q6JYQ7 http://www 100.0% identity
内容的提问来源于stack exchange,提问作者Susheel Busi
相关产品推荐
相关产品推荐

