如何加速含多个sed命令的Bash for循环?可使用GNU parallel吗?
优化Bash脚本加速处理read_*文件
我写了一段处理read_*格式文件的Bash循环脚本:
for i in read_* ; do cut -f1 $i | sponge $i sed -i '1 s/^/>/g' $i sed -i '3 s/^/>ref\n/g' $i sed -i '4d' $i sed -i '1h;2H;1,2d;4G' $i mv $i $i.fasta done
这个脚本用到了cut、多次sed调用和mv操作,其中sed -i '1h;2H;1,2d;4G' $i是用来交换第2行和第4行的。我想加速这个处理流程,有没有可行的方法?比如用GNU parallel?
输入示例:
sampleid 97 stuff 2086 42 213M = 3322 1431 TATTTAGGGAAGATCTGGCCTTCCTACAAGGGAAGGCCAGGGAATTTTCTTCAGAGCAGA |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TTTTTAGGGAAGATCTGGCCTTCCTACAAGGGAAGGCCAGGGAATTTTCTTCAGAGCAGA
期望输出:
>ref TTTTTAGGGAAGATCTGGCCTTCCTACAAGGGAAGGCCAGGGAATTTTCTTCAGAGCAGA >sampleid TATTTAGGGAAGATCTGGCCTTCCTACAAGGGAAGGCCAGGGAATTTTCTTCAGAGCAGA
优化方案:先精简单文件逻辑,再并行处理
第一步:精简单文件处理,减少IO开销
原来的脚本多次调用sed -i会反复读写同一个文件,IO开销极大。可以用awk一次性完成所有逻辑,只读取一次文件、输出一次结果:
process_file() { local file="$1" awk ' NR==1 { sample=$1; next } NR==2 { seq=$0; next } NR==4 { ref_seq=$0 } END { print ">ref" print ref_seq print ">" sample print seq } ' "$file" > "${file}.fasta" }
这个函数直接提取输入文件的关键内容,按期望格式输出到对应的.fasta文件,完全替代原来的cut+多次sed操作,效率提升明显。
第二步:用GNU parallel并行处理多文件
如果有大量read_*文件,用GNU parallel可以利用CPU多核同时处理多个文件,进一步提升速度:
方式1:调用预定义函数
# 导出函数到子shell,让parallel能识别 export -f process_file # 并行处理所有read_*文件 parallel process_file ::: read_*
方式2:直接传入awk命令
如果不想定义函数,也可以直接写单行命令:
parallel 'awk "NR==1 {s=\$1;next} NR==2 {seq=\$0;next} NR==4 {r=\$0} END {print \">ref\";print r;print \">\"s;print seq}" {} > {}.fasta' ::: read_*
优化后的优势
- 降低IO开销:原来的脚本对每个文件做了5次读写操作,优化后仅1次读、1次写,IO压力大幅降低。
- 多核并行:GNU parallel会根据CPU核心数自动分配任务,处理大量文件时速度提升倍数接近核心数。
- 逻辑更清晰:用awk一次性实现所有转换逻辑,避免了多次sed命令的复杂拼接,更易维护。
内容的提问来源于stack exchange,提问作者SaltedPork
相关产品推荐
相关产品推荐

