awk与sed管道命令效率低,求优化scaffold转BED范围文件脚本
问题分析
你的现有方案效率低的核心原因是重复读取输入文件:每处理一个scaffold就重新扫描一遍整个$indiv.txt,文件越大,冗余IO带来的性能损耗越夸张。我们可以用单趟awk完成所有逻辑,只读取一次文件,效率会提升几个数量级。
高效实现代码
脚本版(可读性更好)
创建一个collapse_to_bed.awk文件:
BEGIN { OFS = "\t" # 设置输出分隔符为制表符,符合BED格式规范 } NR == 1 { next # 跳过表头行 } { # 遇到新的scaffold时,先输出上一个scaffold的最后一个区间 if ($1 != curr_scaff) { if (curr_scaff != "") { print curr_scaff, start, end } curr_scaff = $1 start = $2 end = $2 } else { # 同一个scaffold下,判断位点是否连续 if ($2 == end + 1) { end = $2 # 连续则扩展区间终点 } else { print curr_scaff, start, end # 不连续则输出当前区间 start = $2 end = $2 } } } END { # 输出最后一个scaffold的最后一个区间,避免遗漏 print curr_scaff, start, end }
执行命令:
awk -f collapse_to_bed.awk $indiv.txt > $indiv.bed
单行版(快速执行)
如果不想单独存脚本,可以用单行命令:
awk 'BEGIN{OFS="\t"} NR==1{next} {if($1!=curr){if(curr!="")print curr,s,e;curr=$1;s=$2;e=$2}else{if($2==e+1)e=$2;else{print curr,s,e;s=$2;e=$2}}} END{print curr,s,e}' $indiv.txt > $indiv.bed
关键优化点说明
- 单趟扫描:整个逻辑只读取一次输入文件,时间复杂度从原来的
O(n*m)(n为scaffold数量,m为文件行数)降到O(m),大文件下性能提升极其明显。 - 状态跟踪:用
curr_scaff、start、end三个变量实时跟踪当前处理的scaffold和区间状态,无需额外生成中间文件或多进程调用。 - 格式兼容:默认用制表符分隔输出,符合BED文件的通用格式要求(如果需要空格分隔,把
OFS="\t"改成OFS=" "即可)。
额外提示
如果你的输入文件scaffold或位点是乱序的,需要先排序再处理:
sort -k1,1n -k2,2n $indiv.txt | awk 'BEGIN{OFS="\t"} NR==1{next} {if($1!=curr){if(curr!="")print curr,s,e;curr=$1;s=$2;e=$2}else{if($2==e+1)e=$2;else{print curr,s,e;s=$2;e=$2}}} END{print curr,s,e}' > $indiv.bed
内容的提问来源于stack exchange,提问作者mernster
相关产品推荐
相关产品推荐

