列から情報を抽出する[閉じる]

列から情報を抽出する[閉じる]

次のファイルがあります。

chr1    HAVANA  exon    12613   12721   .   +   .   gene_id "ENSG00000223972.5"; transcript_id "ENST00000456328.2"; gene_type "transcribed_unprocessed_pseudogene"; gene_name "DDX11L1"; transcript_type "processed_transcript"; transcript_name "DDX11L1-202"; exon_number 2; exon_id "ENSE00003582793.1"; level 2; transcript_support_level "1"; tag "basic"; havana_gene "OTTHUMG00000000961.2"; havana_transcript "OTTHUMT00000362751.1";
chr1    HAVANA  exon    13221   14409   .   +   .   gene_id "ENSG00000223972.5"; transcript_id "ENST00000456328.2"; gene_type "transcribed_unprocessed_pseudogene"; gene_name "DDX11L1"; transcript_type "processed_transcript"; transcript_name "DDX11L1-202"; exon_number 3; exon_id "ENSE00002312635.1"; level 2; transcript_support_level "1"; tag "basic"; havana_gene "OTTHUMG00000000961.2"; havana_transcript "OTTHUMT00000362751.1";

gene_id、gene_nameの値と最初の8列(ファイルはタブで区切られています)を抽出したいと思います。私はこれを行うスクリプトをPerlで書いていますが、awk、sedなどでこれを行うことができる1行のスクリプトを探しています。

PS。ファイルはタブで区切られ、9つの列で構成されています。列9の値はスペースで区切ります。

私の出力は次のようになります。

chr1    HAVANA  exon    12613   12721   .   +   .   ENSG00000223972.5   DDX11L1
chr1    HAVANA  exon    13221   14409   .   +   .   ENSG00000223972.5   DDX11L1

答え1

次のawkスクリプトでは、列9に任意の順序でデータを含めることができると想定しています。

このコードは列を分割し、;その後にオプションのスペースが続きます。次に、結果要素を繰り返し、その要素をスペースに基づいてキーと値のペアに分割します。キー(スペースの左側にあるもの)が2つの文字列のうちgene_idの1つである場合、またはgene_nameそのキーの値が記憶されます。列9の解析は、2つの文字列が見つかると終了し、その後列が再作成され、変更された行が印刷されます。

このコードはすべての入力を削除します。いいえgene_idとを含みますgene_name

BEGIN {
    FS = OFS = "\t"
}

{
    n = split($9, a, "; ?")

    found = 0;
    for (i = 1; i <= n; ++i)
        if (split(a[i], b, " ") == 2) {
            if (b[1] == "gene_id") {
                gene_id = b[2]
                ++found
            } else if (b[1] == "gene_name") {
                gene_name = b[2]
                ++found
            }

            if (found == 2) break
        }

    if (found == 2) {
        $9 = gene_id " " gene_name
        print
    }
}

提供されたデータをテストします。

$ awk -f script.awk <file
chr1    HAVANA  exon    12613   12721   .       +       .       "ENSG00000223972.5" "DDX11L1"
chr1    HAVANA  exon    13221   14409   .       +       .       "ENSG00000223972.5" "DDX11L1"

値から二重引用符を削除するには、以下を変更します。

if (found == 2) {
    $9 = gene_id " " gene_name
    print
}

入力する

if (found == 2) {
    gsub("\"", "", gene_id)
    gsub("\"", "", gene_name)
    $9 = gene_id " " gene_name
    print
}

これにより、遺伝子名とIDのすべての二重引用符が削除されます。

if (found == 2) {
    gene_id = substr(gene_id, 2, length(gene_id) - 2)
    gene_name = substr(gene_name, 2, length(gene_name) - 2)
    $9 = gene_id " " gene_name
    print
}

両方の値から最初の文字と最後の文字を削除します。

答え2

Perlコード1行。少し短く演奏することもできましたが、かなり明確だと思います。

perl -F'\t' -lane '
    if (($id, $name) = / \b gene_id \s+ " ([^"]+) .+ \b gene_name \s+ " ([^"]+)/x) {
        print join "\t", @F[0..7], $id, $name;
    }
' file

もう少し「スマート」にする:

perl -F'\t' -E '$,="\t"; say @F[0..7], $g{id}, $g{name} if %g = /\bgene_(id|name)\s+"([^"]+)/g' file

答え3

awk '{ print $1 "\t" $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8 "\t" $10 "\t" $16 ; } ' filename > output

引用符とセミコロンなし:

awk '{ print $1 "\t" $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8 "\t" $10 "\t" $16 ; }' filename | sed -e 's/;//g; s/\"//g;' > output

awkを使用すると、より正確になります。

awk '{ ORS=" "; print $1 "\t" $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8 "\t"; gsub(";", "", $10); gsub("\"", "", $10); print $10 "\t"; gsub(";", "", $16) ; gsub("\"", "", $16); print $16 ; ORS="\n" ; print " "; } ' filename > output

関連情報