繁体   English   中英

awk计数出现次数

[英]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
  • Awk脚本由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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM