求助:用awk分割Geneid字段并拼接至Chr列的正确实现方法
解决制表符分隔文件的字段修改问题
需求说明
现有一个制表符分隔的输入文件,结构如下:
Geneid Chr Start End Strand Length WI_D_9_18_21_A_contigs_sorted.bam 1_1 c_1246 1 1395 + 1395 1028 1_2 c_1246 1407 2168 + 762 821 1_3 c_1246 2198 2971 + 774 874 1_4 c_1246 2986 3969 + 984 938 1_5 c_1246 4163 5047 + 885 874 1_6 c_1246 5085 5333 + 249 362 1_7 c_1246 5549 5878 + 330 493 1_8 c_1246 6057 6713 + 657 696
需要生成一个新的制表符分隔文件,包含以下列:
- Geneid(原第1列)
- 修改后的Chr:将Geneid字段中下划线后的数字部分追加到原Chr字段末尾,格式为
Chr_数字 - Length(原第6列)
- 原第7列
期望输出如下:
Geneid Chr Length WI_D_9_18_21_A_contigs_sorted.bam 1_1 c_1246_1 1395 1028 1_2 c_1246_2 762 821 1_3 c_1246_3 774 874 1_4 c_1246_4 984 938 1_5 c_1246_5 885 874 1_6 c_1246_6 249 362 1_7 c_1246_7 330 493 1_8 c_1246_8 657 696 1_9 c_1246_9 663 725
错误尝试
尝试了以下awk命令,但无法正确追加数字,输出的Chr字段末尾只有下划线:
awk -F ' ' '{OFS = FS} FNR<=1{next} NR>2 {split($1,a,_); $2 = $2 "_" a[$2];} 1 {print $1,$2,$6,$7}' WI_D_9_18_21_A_bin.6_fC_gene_coverage.tsv > test.txt awk -F ' ' '{OFS = FS} FNR<=1{next} {n[$1,$2]=split($1,a,"_");} NR>1 {print $1,$2 "_" n[$2],$6,$7}' WI_D_9_18_21_A_bin.6_fC_gene_coverage.tsv > test.txt awk -F ' ' '{OFS = FS} FNR<=1{next} {split($1,a,"_");next} FNR>1 {print $1,$2 "_" a[$2],$6,$7}' WI_D_9_18_21_A_bin.6_fC_gene_coverage.tsv > test.txt
错误输出示例:
Geneid Chr Length WI_D_9_18_21_A_contigs_sorted.bam 1_1 c_1246_ 1395 1028 1_2 c_1246_ 762 821 1_3 c_1246_ 774 874 1_4 c_1246_ 984 938 1_5 c_1246_ 885 874 1_6 c_1246_ 249 362 1_7 c_1246_ 330 493 1_8 c_1246_ 657 696 1_9 c_1246_ 663 725
正确解法
问题出在split后的数组索引使用错误:当用split($1,a,"_")分割Geneid(如1_1)时,数组a的a[1]是1,a[2]是下划线后的数字部分,你之前错误地用了a[$2],这会取数组中不存在的索引,导致输出空值。
正确的awk命令如下:
awk -F '\t' -v OFS='\t' ' NR==1 {print $1, $2, $6, $7; next} { split($1, a, "_") new_chr = $2 "_" a[2] print $1, new_chr, $6, $7 } ' WI_D_9_18_21_A_bin.6_fC_gene_coverage.tsv > test.txt
命令解释:
-F '\t' -v OFS='\t':指定输入和输出的分隔符都是制表符,确保列对齐。NR==1 {print $1, $2, $6, $7; next}:处理第一行表头,直接输出需要的列,然后跳过后续处理。split($1, a, "_"):将Geneid字段按下划线分割到数组a中。new_chr = $2 "_" a[2]:拼接原Chr字段和Geneid分割后的第二部分数字。print $1, new_chr, $6, $7:输出最终需要的四列。
也可以用更简洁的写法,利用awk的字符串匹配特性,不用split:
awk -F '\t' -v OFS='\t' ' NR==1 {print $1, $2, $6, $7; next} {print $1, $2 "_" substr($1, index($1,"_")+1), $6, $7} ' WI_D_9_18_21_A_bin.6_fC_gene_coverage.tsv > test.txt
这个写法通过index($1,"_")找到下划线的位置,用substr截取后面的数字部分,直接拼接。
内容的提问来源于stack exchange,提问作者Linton
相关产品推荐
相关产品推荐

