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{}
入力ファイルの最後の行を読んだ後、一度だけ実行します。したがって、$1
andは$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{}
ブロックの外にあるので、最後だけでなくすべての行で実行されます。
それはすべてです。シェルループは不要で、数秒しかかからない。