awkの行と列を繰り返して、各セルの特定の部分文字列を計算します。

awkの行と列を繰り返して、各セルの特定の部分文字列を計算します。

138の最初のヘッダー行(#で始まる)と、行のその他のデータ(snp(322045))と列の一部の情報を持つ患者(最初の10行)を含む.vcfファイルがあります。スクリプトbashを使用して各行の数を計算します。 "0|0" (初期部分) と他の対応する行のセル数: ここに私のスクリプトがあります。

for j in {139..322045}

    do
     c=0
     awk -v var=$c -v j=$j 'NR==j{for(i=10; i<=NF; i++) {if(substr($i,1,3)!="0|0") var++}} END{ print $1 ":" $2 "\t" var }' file.vcf >> out.txt
    done

これは入力する:

> #<info>
> #..
> # . . . 
21  9411245  x  C   A   505  PASS   AC=2   GT:AD:DP:GQ:PL   0|0:11  0|0:12
21  9411246  y  C   T   505  PASS   AC=2   GT:AD:DP:GQ:PL   0|0:11  1|0:13

(タブで区切られた列)次に、リンクされた最初と2番目の列を印刷します。そしてcount;しかし、完全に動作しません。 2行だけのサブセットを使用すると、完全に機能します。これは結果

21:48111872 2
21:48111872 1
21:48111872 0
21:48111872 2

行を繰り返します

どうすれば解決できますか?事前に感謝し、問題を解決するには簡単な説明を書いてください。

気づく計算に時間がかかります。 ({139..160}にも使用されます)

ベストアンサー1

うまくいかないのは、印刷$1中で$2ブロックにあるからですEND{}END{}入力ファイルの最後の行を読んだ後、一度だけ実行します。したがって、$1andは$2常に最後の行の最初と2番目のフィールドになります。

それにもかかわらず、これはテキストファイルを解析する非常に非効率的な方法です。ループが繰り返されるたびに内容全体を読み続けています。シェルループは非常に遅い。だからあなたは非常に遅いループを使用していますそして不必要に何千行ものawkを繰り返し読みます。

シェルループを使用する代わりに、awkですべての操作を実行してください。

$ awk -F"\t" '/^[^#]/{var=0; for(i=10; i<=NF; i++) {if(substr($i,1,3)!="0|0") var++} print $1 ":" $2 "\t" var }' foo.vcf 
21:9411245  0
21:9411246  1

またはもう少し簡潔に言えば、

awk -F"\t" '/^[^#]/{
        var=0; 
        for(i=10; i<=NF; i++) {
            if(substr($i,1,3)!="0|0"){
                var++
            } 
        }
        print $1 ":" $2 "\t" var 
    }' foo.vcf 

説明する

  • -F"\t":入力フィールド区切り記号をタブに設定します。
  • /^[^#]/{ ... }:()以外の文字で始まる行に対してのみこれを実行します(/^a/で始まる行と一致します)。a#[^#]
  • var=0;var各入力ラインを再びゼロに設定します。
  • for(i=10; i<=NF; i++) {if(substr($i,1,3)!="0|0") var++}:これは、遺伝子型ではないことが見つかった回数を数える元のコードです0|0
  • print $1 ":" $2 "\t" var:再び、コードはEND{}ブロックの外にあるので、最後だけでなくすべての行で実行されます。

それはすべてです。シェルループは不要で、数秒しかかからない。

おすすめ記事