fri*_*day 5 sed awk regular-expression bioinformatics
我有一个看起来像这样的文件(> 80,000 行):
chr1 GTF2GFF chromosome 1 249213345 . . . ID=chr1;Name=chr1
chr1 GTF2GFF gene 11874 14408 . + . ID=DDX11L1;Note=unknown;Name=DDX11L1
chr1 GTF2GFF exon 11874 12227 . + . Parent=NR_046018_1
chr1 GTF2GFF exon 12613 12721 . + . Parent=NR_046018_1
chr1 GTF2GFF exon 13221 14408 . + . Parent=NR_046018_1
chr1 GTF2GFF gene 14362 29370 . - . ID=WASH7P;Note=unknown;Name=WASH7P
chr1 GTF2GFF exon 14362 14829 . - . Parent=NR_024540
chr1 GTF2GFF exon 14970 15038 . - . Parent=NR_024540
chr1 GTF2GFF exon 15796 15947 . - . Parent=NR_024540
chr1 GTF2GFF exon 16607 16765 . - . Parent=NR_024540
chr1 GTF2GFF exon 16858 17055 . - . Parent=NR_024540
chr1 GTF2GFF exon 17233 17368 . - . Parent=NR_024540
chr1 GTF2GFF exon 17606 17742 . - . Parent=NR_024540
chr1 GTF2GFF exon 17915 18061 . - . Parent=NR_024540
chr1 GTF2GFF exon 18268 18366 . - . Parent=NR_024540
chr1 GTF2GFF exon 24738 24891 . - . Parent=NR_024540
chr1 GTF2GFF exon 29321 29370 . - . Parent=NR_024540
chr1 GTF2GFF gene 34611 36081 . - . ID=FAM138A;Note=unknown;Name=FAM138A
chr1 GTF2GFF exon 34611 35174 . - . Parent=NR_026818
chr1 GTF2GFF exon 35277 35481 . - . Parent=NR_026818
Run Code Online (Sandbox Code Playgroud)
我只想提取第三个字段中包含“基因”的行,并重新排列第 9 个字段以仅包含 ID 值(例如,DDX11L1)。这是所需的输出:
chr1 11874 14408 DDX11L1 . +
chr1 14362 29370 WASH7P . -
chr1 34611 36081 FAM138A . -
Run Code Online (Sandbox Code Playgroud)
使用 awk 我很容易得到了想要的字段:
head -20 genes.gff3 | awk '$3=="gene" {print $1 "\t" $4 "\t" $5 "\t" $9"\t" $6 "\t" $7}'
chr1 11874 14408 ID=DDX11L1;Note=unknown;Name=DDX11L1 . +
chr1 14362 29370 ID=WASH7P;Note=unknown;Name=WASH7P . -
chr1 34611 36081 ID=FAM138A;Note=unknown;Name=FAM138A . -
Run Code Online (Sandbox Code Playgroud)
但我正在努力获取 ID 值。我试过用管道将它传输到 sed:
head -20 genes.gff3 | awk '$3=="gene" {print $1 "\t" $4 "\t" $5 "\t" $9"\t" $6 "\t" $7}' | sed 's/\(^.+\t\)ID=\(\w+\).+\(\t.+$\)/\1\2\3/g'
Run Code Online (Sandbox Code Playgroud)
还有 gsub
head -20 genes.gff3 | awk '$3=="gene" {gsub(/\(^.+\t\)ID=\(\w+\).+\(\t.+$\)/, "\1\2\3", $9); print $1 "\t" $4 "\t" $5 "\t" $9"\t" $6 "\t" $7}'
Run Code Online (Sandbox Code Playgroud)
但结果与单独使用 awk 相同。如何提取 ID 值?我觉得我真的很接近这里的解决方案。
干杯。
该split
函数的字段分隔符是一个正则表达式,因此您可以在=
OR上进行拆分;
。如果您知道以“ID=”$9
开头,那么
awk -v OFS='\t' '
$3 == "gene" {
split($9, id, /[=;]/)
print $1, $4, $5, id[2], $6, $7
}
' genes.gff3
Run Code Online (Sandbox Code Playgroud)
如果“ID=”不一定在字段的开头,那么还有一些工作要做:
awk -v OFS='\t' '
$3 == "gene" {
id = ""
len = split($9, f, /[=;]/)
for (i=1; i<len; i++) {
if (f[i] == "ID") {
id = f[i+1]
break
}
}
print $1, $4, $5, id, $6, $7
}
' genes.gff3
Run Code Online (Sandbox Code Playgroud)
split($9, a, ";")\nprint substr(a[1], 4)\n
Run Code Online (Sandbox Code Playgroud)\nawk 索引从 开始1
。
另一种选择是修改输入字段分隔符 ( FS
)。\nFS
是空格," ",默认为 \xe2\x80\x93 ,它还具有忽略\n前导空格和尾随空格的特殊效果。
另外,可以设置为制表符,而不是使用print $1, \\t, ...
或变体。printf
OFS
修改FS:
\nawk -F" +|;|=" \'\n\n$3 == "gene" {\n printf("%s\\t%s\\t%s\\t%s\\t%s\\t%s\\t\\n",\n $1, $4, $5, $10, $6, $7);\n}\n\' data.file\n
Run Code Online (Sandbox Code Playgroud)\n使用分割:
\nawk \'\n$3 == "gene" {\n split($9, a, ";")\n printf("%s\\t%s\\t%s\\t%s\\t%s\\t%s\\t\\n",\n $1, $4, $5, substr(a[1], 3), $6, $7);\n}\n\' data.file\n
Run Code Online (Sandbox Code Playgroud)\nOFS 和 FS:
\n输出字段分隔符( OFS
) 作为制表符,并FS
在 awk 中替代。\n还更新FS
为包含制表符:
awk \'\nBEGIN {\n FS="[ \\t]+|;|="\n OFS="\\t"\n}\n$3 == "gene" {\n print $1, $4, $5, $10, $6, $7\n}\n\n\' data.file\n
Run Code Online (Sandbox Code Playgroud)\nGawk 手册\xe2\x80\x93 当事物是 awk 的 gawk 扩展时,通常会注明。
\n