遍历ID列表批量统计两列匹配计数的awk脚本问题求解
问题原因
你写的脚本输出全为0,且无法得到预期结果,核心有3个错误:
- 分隔符设置错误:你示例的blastp结果是空白(空格/制表符)分隔,但awk命令里加了
-F,指定逗号为分隔符,无法正确拆分列 - 变量传递错误:shell变量
$i写在awk的单引号内部时,awk无法识别外部shell变量,会把$i当成自身未定义的空变量,永远匹配不到内容 - 逻辑覆盖不全:你写的循环仅判断
$1==$i && $2==$i,只能统计两列ID相同的组合,完全无法覆盖A-B、A-C这类跨基因组的不同ID配对,就算跑通也拿不到全量结果。
最优解决方案
不需要写shell循环反复读取文件,单次awk遍历即可完成全量组合统计,哪怕是几GB的blast结果文件也能快速处理,命令如下:
awk '{pair[$1"\t"$2]++} END{for(k in pair) print k"\t"pair[k]}' 你的blast结果文件 > 配对计数结果.txt
命令逻辑说明:
- awk默认将连续空白(空格、制表符)识别为列分隔符,正好匹配你的文件格式,不需要额外指定
-F参数 - 每读取一行,就将第1列、第2列用制表符拼接作为组合键,对应计数累加1
- 读完整个文件后,遍历所有存储的组合键,输出「queryID subjectID 出现次数」,和你期望的输出格式完全一致。
如果你需要仅统计ID.txt中列出的基因组ID对应的组合(过滤掉不在列表内的杂ID),可以使用带白名单过滤的版本:
awk ' BEGIN { while ((getline id < "ID.txt") > 0) valid[id] = 1 close("ID.txt") } valid[$1] && valid[$2] { pair[$1"\t"$2]++ } END { for (k in pair) print k"\t"pair[k] } ' 你的blast结果文件 > 过滤后配对计数结果.txt
不推荐的写法说明
如果你硬要用shell循环实现,需要通过-v参数向awk传递外部变量,且要做两层循环遍历所有ID两两组合,但这种写法会重复读取文件上百甚至上万次,大文件下效率极低,示例如下(不建议使用):
# 性能极差,仅作语法参考 while read -r qid; do while read -r sid; do cnt=$(awk -v q="$qid" -v s="$sid" '$1==q && $2==s' 你的blast结果文件 | wc -l) echo -e "$qid\t$sid\t$cnt" done < ID.txt done < ID.txt
内容的提问来源于stack exchange,提问作者btredcup
相关产品推荐
相关产品推荐

