簡體   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