我有一个 .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
(各列以制表符分隔)然后我打印由 : 链接的第一列和第二列以及计数;但它不能完全工作,如果我使用仅包含 2 行的子集,它可以完美工作。这是结果
21:48111872 2
21:48111872 1
21:48111872 0
21:48111872 2
它重复行
我该如何解决它?提前致谢,如果您修复了它,请写一个简短的解释。
注意计算它需要很多时间(也用于 {139..160})
答案1
它不起作用的原因是您正在打印$1
并$2
在块中END{}
。END{}
仅在读取输入文件的最后一行后运行一次。所以$1
和$2
永远是最后一行的第一个和第二个字段。
无论如何,这是一种极其低效的解析文本文件的方法。您正在为循环的每次迭代阅读整个内容。 shell 循环是非常慢的。所以你正在使用一个非常慢的循环和你不必要地一遍又一遍地阅读 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 循环,并且只需几秒钟。