使用awk修改大文本文件列值时遇语法错误,求解决方法
修正AWK命令以修改GTF文件的坐标列
问题描述
我有一个类似GTF格式的文本文件,每行以chr开头,前8列用制表符分隔,第9列是属性列表(分号分隔)。示例内容如下:
chr1 HAVANA transcript 12010 13670 . + . gene_id "ENSG00000223972.4"; transcript_id "ENST00000450305.2"; gene_type "pseudogene"; gene_status "KNOWN"; gene_name "DDX11L1"; transcript_type "transcribed_unprocessed_pseudogene"; transcript_status "KNOWN"; transcript_name "DDX11L1-001"; level 2; ont "PGO:0000005"; ont "PGO:0000019"; havana_gene "OTTHUMG00000000961.2"; havana_transcript "OTTHUMT00000002844.2"; chr2 HAVANA exon 12010 12057 . + . gene_id "ENSG00000223972.4"; transcript_id "ENST00000450305.2"; gene_type "pseudogene"; gene_status "KNOWN"; gene_name "DDX11L1"; transcript_type "transcribed_unprocessed_pseudogene"; transcript_status "KNOWN"; transcript_name "DDX11L1-001"; exon_number 1; exon_id "ENSE00001948541.1"; level 2; ont "PGO:0000005"; ont "PGO:0000019"; havana_gene "OTTHUMG00000000961.2"; havana_transcript "OTTHUMT00000002844.2"; chr3 HAVANA exon 12179 12227 . + . gene_id "ENSG00000223972.4"; transcript_id "ENST00000450305.2"; gene_type "pseudogene"; gene_status "KNOWN"; gene_name "DDX11L1"; transcript_type "transcribed_unprocessed_pseudogene"; transcript_status "KNOWN"; transcript_name "DDX11L1-001"; exon_number 2; exon_id "ENSE00001671638.2"; level 2; ont "PGO:0000005"; ont "PGO:0000019"; havana_gene "OTTHUMG00000000961.2"; havana_transcript "OTTHUMT00000002844.2";
我的需求是生成新文件,仅修改第4、5列:
- 新第4列 = 原第4列值 - 12
- 新第5列 = 原第4列值 + 50
我尝试了以下AWK命令:
awk 'BEGIN { FS="\t;" } {print $1"\t"$2"\t"$3"\t"$4=$4-12"\t"$5=$4+50"\t"$6"\t"$7"\t"$8"\t"$9" "$10";"$11" "$12";"$13" "$14";"$15" "$16";"$17" "$18";"$19" "$20";"$21" "$22";"$23" "$24";"$25" "$26";"$27" "$28";"$29" "$30";"$31" "$32";"$33" "$34";"$35" "$36";"$37" "$38";" }' input.txt > test2.txt
但运行时出现语法错误:
awk: cmd. line:1: BEGIN { FS="\t;" } {print $1"\t"$2"\t"$3"\t"$4=$4-12"\t"$5=$4+50"\t"$6"\t"$7"\t"$8"\t"$9" "$10";"$11" "$12";"$13" "$14";"$15" "$16";"$17" "$18";"$19" "$20";"$21" "$22";"$23" "$24";"$25" "$26";"$27" "$28";"$29" "$30";"$31" "$32 ";" $33" "$34";"$35" "$36";"$37" "$38";" } awk: cmd. line:1: ^ syntax error awk: cmd. line:1: BEGIN { FS="\t;" } {print $1"\t"$2"\t"$3"\t"$4=$4-12"\t"$5=$4+50"\t"$6"\t"$7"\t"$8"\t"$9" "$10";"$11" "$12";"$13" "$14";"$15" "$16";"$17" "$18";"$19" "$20";"$21" "$22";"$23" "$24";"$25" "$26";"$27" "$28";"$29" "$30";"$31" "$32 ";" $33" "$34";"$35" "$36";"$37" "$38";" } awk: cmd. line:1: ^ syntax error
问题分析
你的命令有几个关键问题:
- 字段分隔符(FS)设置错误:你设置
FS="\t;"表示字段是由"制表符+分号"组合分隔,但实际文件的前8列是单独用制表符分隔,第9列的属性是用"分号+空格"分隔。这个错误会导致AWK把字段拆得混乱,后续的$9、$10等都不是你期望的内容。 - print语句中的赋值语法错误:在
print中直接写$4=$4-12这种赋值操作,会导致语法解析错误。AWK的print输出的是表达式结果,但这种嵌套赋值的写法不符合语法规范,而且会修改$4的值,导致后续计算$5=$4+50时用的是修改后的$4,而非原始值。 - 手动拼接字段过于繁琐且易出错:你手动拼接每个字段的方式不仅冗长,还容易出现符号错误(比如你命令里的
$32 ";" $33多了空格)。
解决方案
我们可以简化命令,利用AWK的字段替换功能,同时保留原始文件的格式:
awk 'BEGIN {OFS="\t"} {orig_start = $4; $4 = orig_start - 12; $5 = orig_start + 50; print $0}' input.txt > test2.txt
命令解释:
BEGIN {OFS="\t"}:设置输出字段分隔符为制表符,确保输出的列分隔和原文件一致。orig_start = $4:先保存原始第4列的值,避免修改$4后影响第5列的计算。$4 = orig_start -12:将第4列替换为原始值减12。$5 = orig_start +50:将第5列替换为原始值加50(不管原来的第5列是什么)。print $0:输出修改后的整行内容,AWK会自动用OFS分隔所有字段,包括后面的属性列。
验证结果
运行这个命令后,你的示例文件第一行会变成:
chr1 HAVANA transcript 11998 12060 . + . gene_id "ENSG00000223972.4"; transcript_id "ENST00000450305.2"; gene_type "pseudogene"; gene_status "KNOWN"; gene_name "DDX11L1"; transcript_type "transcribed_unprocessed_pseudogene"; transcript_status "KNOWN"; transcript_name "DDX11L1-001"; level 2; ont "PGO:0000005"; ont "PGO:0000019"; havana_gene "OTTHUMG00000000961.2"; havana_transcript "OTTHUMT00000002844.2";
可以看到第4列是12010-12=11998,第5列是12010+50=12060,完全符合需求。
内容的提问来源于stack exchange,提问作者ARM
相关产品推荐
相关产品推荐

