当字段$2为rev时对$4、$5字段执行reverse与tr转换的技术需求
问题描述
输入文本
m64071_220512_054244/12584899/ccs rev pet047-10055 ACGTGCGACCTTGTGA TTGAGGGTTCAAACGTGCGACCTTGTGA m64071_220512_054244/128321000/ccs rev pet047-10055 ACGTGCGACCTTGTGA TTGAGGGTTCAAACGTGCGACCTTGTGA m64071_220512_054244/132186699/ccs fwd pet047-10055 TCACAAGGTCGCACGT TCACAAGGTCGCACGTTTGAACCCTCAA m64071_220512_054244/134874748/ccs fwd pet047-10055 TCACAAGGTCGCACGT TCACAAGGTCGCACGTTTGAACCCTCAA
需求
仅当第2个字段值为rev时,对第4、5字段执行反转字符串+碱基互补转换(ATGC ↔ TACG);fwd行保持原样。
预期输出
m64071_220512_054244/12584899/ccs rev pet047-10055 TCACAAGGTCGCACGT TCACAAGGTCGCACGTTTGAACCCTCAA m64071_220512_054244/128321000/ccs rev pet047-10055 TCACAAGGTCGCACGT TCACAAGGTCGCACGTTTGAACCCTCAA m64071_220512_054244/132186699/ccs fwd pet047-10055 TCACAAGGTCGCACGT TCACAAGGTCGCACGTTTGAACCCTCAA m64071_220512_054244/134874748/ccs fwd pet047-10055 TCACAAGGTCGCACGT TCACAAGGTCGCACGTTTGAACCCTCAA
原尝试的问题
Perl命令问题
原命令逻辑和语法都有问题:
perl -lpe 'if(/rev/) {$rev=/rev/;next}; if ($rev) {$F[4,5]=~tr/ATGC/TACG/; $F[4,5]=reverse $F[4,5]; print "@F"}' file
- 未加
-a参数,无法自动拆分字段到@F数组,数组为空 - 匹配到
rev后直接next跳过处理,后续逻辑根本不会执行 - 碱基转换和反转的顺序逻辑混乱,且未针对目标字段正确操作
Awk命令问题
原命令存在变量错误和效率问题:
awk '{ if($2==rev) { cmd1="echo \047" $4 "\047 | rev | tr \047ATGC\047 \047TACG\047" cmd2="echo \047" $5 "\047 | rev | tr \047ATGC\047 \047TACG\047" newVar1=((cmd1 | getline line) > 0 ? line : "failed") newVar2=((cmd2 | getline line) > 0 ? line : "failed") close(cmd) print $1, $2, $3, newVar1, newVar2 } else {print} }' file
$2==rev中rev是未定义变量,应该写$2=="rev"close(cmd)中的cmd未定义,需分别关闭cmd1和cmd2- 调用外部
rev/tr命令效率低,Awk本身可实现对应功能
正确解决方案
方案1:Perl命令
利用Perl内置的字段拆分和字符串处理能力,无需外部命令:
perl -alne ' if ($F[1] eq "rev") { # 处理第4、5字段(数组索引3、4) for my $i (3,4) { $F[$i] = reverse $F[$i]; $F[$i] =~ tr/ATGC/TACG/; } } print join(" ", @F); ' file
-a参数自动按空格拆分字段到@F数组(索引从0开始)- 直接在Perl内完成反转+互补,效率更高
- 逻辑清晰,严格匹配
rev字段后处理目标内容
方案2:Awk命令
用Awk自定义函数实现反转和互补,避免外部命令开销:
# 定义碱基互补转换函数 function complement(s) { gsub(/A/, "X", s); gsub(/T/, "A", s); gsub(/X/, "T", s); gsub(/G/, "Y", s); gsub(/C/, "G", s); gsub(/Y/, "C", s); return s; } # 定义字符串反转函数 function reverse(s) { res = ""; for (i = length(s); i > 0; i--) { res = res substr(s, i, 1); } return res; } { if ($2 == "rev") { $4 = complement(reverse($4)); $5 = complement(reverse($5)); } print $0; } ' file
- 纯Awk内置逻辑实现,无需依赖外部工具
- 直接修改对应字段后打印整行,输出格式和输入一致
内容的提问来源于stack exchange,提问作者pedro
相关产品推荐
相关产品推荐

