awkを使用して列番号の代わりに名前でフィールドを抽出するには?

awkを使用して列番号の代わりに名前でフィールドを抽出するには?

私は大きなものを持っていますgtf。ここでeg.gtf次のように共有します。

chr22   Cufflinks       transcript      10695955        10696708        .       +       .       transcript_id "first_11345700"; gene_id "XLOC_158970"; gene_name "XLOC_158970"; oId "TCONS_00353198"; class_code "u"; tss_id "TSS369767"; original_gene_id "XLOC_158970";
chr22   Cufflinks       exon    10702915        10703826        .       +       .       transcript_id "first_11345701"; gene_id "ENSG00000277248.1"; gene_name "ENSG00000277248.1"; exon_number "1"; original_gene_id "ENSG00000277248.1";
chr22   Cufflinks       transcript      10702915        10707278        .       +       .       transcript_id "first_11345701"; gene_id "ENSG00000277248.1"; gene_name "ENSG00000277248.1"; oId "TCONS_00353199"; class_code "u"; tss_id "TSS369769"; original_gene_id "ENSG00000277248.1";

awk次の列番号を使用して必須フィールドを抽出しました。

cat eg.gtf | awk 'OFS="\t" {if ($3=="transcript") {print $1,$4-1,$5,$12,$7}}' | tr -d '";'

出力は次のとおりです。

chr22   10695954    10696708    XLOC_158970 +
chr22   10702914    10707278    ENSG00000277248.1   +

12コマンドに列番号を使用したくありませんが、awk名前のあるフィールドを抽出したいと思います。

メモ: 12th column has different names, starting with E or X or M or N or S

12コマンドに列番号を指定せずに12番目のフィールドをどのように取得できますかawkgene_id列11の用語を使用してフィールド12を取得する方法はありますか?

答え1

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ cat tst.awk
BEGIN {
    FS=OFS="\t"
}
$3 == "transcript" {
    n = split($NF,tmp,/[; "]+/)
    for ( i=1; i<n; i+=2 ) {
        vals[tmp[i]] = tmp[i+1]
    }
    print $1, $4-1, $5, vals["gene_id"], $7
}

$ awk -f tst.awk file
chr22   10695954    10696708    XLOC_158970 +
chr22   10702914    10707278    ENSG00000277248.1   +

答え2

GTFはタブ区切り形式なので、サブフィールドの順序を信頼できません。代わりにテキスト解析を使用する必要があります。私はPerlを使って次のことをします。

$ perl -F'\t' -lane '
    if($F[2] eq "transcript"){
        $gene_id = /gene_id\s*"([^"]+)"/ ? $1 : "None"; 
        print join("\t",$F[0],$F[3]-1,$F[4],$gene_id,$F[6])
    }' file
chr22   10695954    10696708    XLOC_158970 +
chr22   10702914    10707278    ENSG00000277248.1   +

これは、遺伝子名がない場合は「なし」で印刷するという利点があります(例えば、コード化されていない転写物には遺伝子名がないか、不明な転写物などがある可能性があります)。

答え3

使用ミラー()また、入力がタブで区切られたファイルで、9番目のフィールドが -- 区切りのキーと値のフィールドで構成されていると仮定しますmlr(キーは二重引用符で囲まれた値文字列でスペースで区切られます)。;

mlr --inidx --ifs tab --otsv --headerless-csv-output \
    filter '$3 == "transcript"' then \
    put '$4 -= 1; $9 = gsub($9, "; ", ";"); $9 = gsub($9, "\"", "")' then \
    nest --explode --pairs --across-fields --nested-fs ';'  --nested-ps ' ' -f 9 then \
    cut -o -f 1,4,5,gene_id,7 file.gtf

これにより、ファイルは整数インデックスタブ区切りフィールドとして読み取られ、ヘッダーなしタブ区切りデータ出力(TSV)が生成されます。 Millerは挿入された引用符について文句を言うため、データをTSVに読み取ることはできません(フィールド自体が引用符でない場合、フィールドに引用符を挿入できません)。

filter3番目のフィールドが文字列以外のすべてのレコードを削除すると、処理が開始されますtranscript

次に、putを使用して4番目のフィールドの値を1ずつ減らします。また、;9番目のフィールド(追加の説明があるフィールド)の各フィールドの後のスペースとすべてのフィールドの二重引用符を削除しました。

このnest --explode仕事は新しい名前付きキーと値のペアを「爆発」して、フィールド9のデータからフィールドを抽出します。

cutその後、そのフィールドを含む目的のフィールドを抽出するために使用できますgene_id

質問のデータを出力します。

chr22   10695954        10696708        XLOC_158970     +
chr22   10702914        10707278        ENSG00000277248.1       +

関連情報