[英]awk Count number of occurrences
我在shell脚本中执行了这个awk命令,以计算$ 4和$ 5的总出现次数。
awk -F" " '{if($4=="A" && $5=="G") {print NR"\t"$0}}' file.txt > ag.txt && cat ag.txt | wc -l
awk -F" " '{if($4=="C" && $5=="T") {print NR"\t"$0}}' file.txt > ct.txt && cat ct.txt | wc -l
awk -F" " '{if($4=="T" && $5=="C") {print NR"\t"$0}}' file.txt > tc.txt && cat ta.txt | wc -l
awk -F" " '{if($4=="T" && $5=="A") {print NR"\t"$0}}' file.txt > ta.txt && cat ta.txt | wc -l
在shell中,输出为####(数字)。 但是我想摆脱> ag.txt && cat ag.txt | wc -l
> ag.txt && cat ag.txt | wc -l
,而是在shell中获取输出,例如AG = ####。
这是输入格式:
>seq1 284 284 A G 27 100 16 11 16 11
>seq1 266 266 C T 27 100 16 11 16 11
>seq1 185 185 T - 24 100 10 14 10 14
>seq1 194 194 T C 24 100 12 12 12 12
>seq1 185 185 T AAA 24 100 10 14 10 14
>seq1 194 194 A G 24 100 12 12 12 12
>seq1 185 185 T A 24 100 10 14 10 14
我想要这样的输出在外壳或文件中出现一次而不是其他模式。
AG 2
CT 1
TC 1
TA 1
是的,您尝试执行的所有操作都可以在awk脚本中完成。 这是我根据条件计算行数的方法:
awk -F" " '$4=="A" && $5=="G" {n++} END {printf("AG = %d\n", n)}' file.txt
condition { statement }
对组成,因此您可以完全消除– if
是隐式的。 n++
都会增加一个计数器。 END
最后一行输入后,魔术条件END
为true。 这是你所追求的吗? 如果只需要行数,为什么还要在输出中添加NR
?
哦,您可能需要确认是否确实需要-F" "
。 默认情况下,awk在空白处分割。 我认为,仅当您的字段包含嵌入式选项卡时才需要此选项。
根据已编辑的问题更新#1 ...
如果您真正想要的是配对计数器,则可以使用awk 数组 。 像这样:
awk '{a[$4 $5]++} END {for (pair in a) printf("%s %d\n", pair, a[pair])}' file.txt
这是细分。
$4
和$5
的数组( a[]
)上的索引。 END
块中,我们在for
循环中遍历数组,并为每个索引打印索引名称和值。 输出将没有任何特定顺序,因为awk不保证数组顺序。 如果您满意,那就足够了。 它也应该非常有效,因为它的最大内存使用量取决于可用组合的总数,这是一个有限的集合。
例:
$ cat file
>seq1 284 284 A G 27 100 16 11 16 11
>seq1 266 266 C T 27 100 16 11 16 11
>seq1 227 227 T C 25 100 13 12 13 12
>seq1 194 194 A G 24 100 12 12 12 12
>seq1 185 185 T A 24 100 10 14 10 14
$ awk '/^>seq/ {a[$4 $5]++} END {for (p in a) printf("%s %d\n", p, a[p])}' file
CT 1
TA 1
TC 1
AG 2
根据修改后的输入数据和以前未记录的要求进行的更新#2 。
有了额外的数据,您仍然可以通过单次运行awk来做到这一点,但是当然,awk脚本随着每个新需求而变得越来越复杂。 让我们将其作为更长的单线尝试:
$ awk 'BEGIN{v["G"]; v["A"]; v["C"]; v["T"]} $4 in v && $5 in v {a[$4 $5]++} END {for (p in a) printf("%s %d\n", p, a[p])}' i
CT 1
TA 1
TC 1
AG 2
首先(在神奇的BEGIN
块中)定义一个数组v[]
来记录“有效”记录,这样可以起作用。 计数器上的条件只是验证$4
和$5
都包含数组的成员。 其他所有都一样。
此时,无论如何脚本都会运行在多行上,我可能会将其分成一个小文件。 它甚至可以是独立脚本。
#!/usr/bin/awk -f
BEGIN {
v["G"]; v["A"]; v["C"]; v["T"]
}
$4 in v && $5 in v {
a[$4 $5]++
}
END {
for (p in a)
printf("%s %d\n", p, a[p])
}
用这种方式更容易阅读。
而且,如果您的目标是仅计算问题中提到的组合,则可以稍微不同地处理数组。
#!/usr/bin/awk -f
BEGIN {
a["AG"]; a["TA"]; a["CT"]; a["TC"]
}
($4 $5) in a {
a[$4 $5]++
}
END {
for (p in a)
printf("%s %d\n", p, a[p])
}
这只会验证已经具有数组索引的东西,每个BEGIN
为NULL。
增量条件中的括号不是必需的,仅为了清楚起见,将其包括在内。
只计算它们,然后打印您关心的那些:
$ awk '{cnt[$4$5]++} END{split("AG CT TC TA",t); for (i=1;i in t;i++) print t[i], cnt[t[i]]+0}' file
AG 2
CT 1
TC 1
TA 1
请注意,对于您输入中未出现的任何目标对,这将产生零计数,例如,如果您也想要计数“ XY”:
$ awk '{cnt[$4$5]++} END{split("AG CT TC TA XY",t); for (i=1;i in t;i++) print t[i], cnt[t[i]]+0}' file
AG 2
CT 1
TC 1
TA 1
XY 0
如果需要,请检查其他解决方案是否也是如此。
实际上,这可能是您真正想要的,只是确保$ 4和$ 5是单个大写字母:
$ awk '$4$5 ~ /^[[:upper:]]{2}$/{cnt[$4$5]++} END{for (i in cnt) print i, cnt[i]}' file
TA 1
AG 2
TC 1
CT 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.