Bash
在 awk 中循環行和列以計算每個單元格的特定子字元串
我有一個 .vcf 文件,其中包含 138 個第一標題行(以 # 開頭)和其他數據(行中的 snp(322045)和列中有一些資訊的患者(前 10 個)。我使用腳本 bash 來計算每個row 該行中與“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
(這些列是製表符分隔的)然後我列印由 : 連結的第 1 列和第 2 列以及計數;但它不能完全工作,如果我使用一個只包含 2 行的子集,它工作得很好。這是結果
21:48111872 2 21:48111872 1 21:48111872 0 21:48111872 2
它重複行
我該如何解決?在此先感謝,如果您修復它,請寫一個簡短的解釋。
注意計算它需要很多時間(也用於 {139..160})
它不起作用的原因是您正在列印
$1
並且$2
在END{}
塊中。END{}
僅在讀取輸入文件的最後一行後執行一次。所以$1
並且$2
將永遠是最後一行的第一個和第二個欄位。無論如何,這是一種非常低效的解析文本文件的方法。您正在閱讀循環的每次迭代的全部內容。而且外殼循環非常慢。因此,您正在使用一個非常慢的循環*,*並且一遍又一遍地不必要地閱讀 awk 中的數千行。
無需使用 shell 循環,只需在 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
回 0。for(i=10; i<=NF; i++) {if(substr($i,1,3)!="0|0") var++}
:這是您的原始程式碼,它計算找到不是的基因型的次數0|0
。print $1 ":" $2 "\t" var
:再次,您的程式碼,但現在在END{}
塊之外,因此它在每一行上執行,而不僅僅是結尾。就是這樣。不需要 shell 循環,它應該只需要幾秒鐘。