首页 > 解决方案 > awk : awk 脚本按条件按列分组

问题描述

我有如下的制表符分隔文件,我正在尝试编写一个 awk 脚本

aaa_log-000592                    2     p      STARTED   7027691  21.7   a1
aaa_log-000592                    28    r      STARTED   7027815  21.7   a2
aaa_log-000592                    33    p      STARTED   7032607  21.7   a3
aaa_log-000592                    33    r      STARTED   7032607  21.7   a4
aaa_log-000592                    43    p      STARTED   7025709  21.7   a5
aaa_log-000592                    43    r      STARTED   7025709  21.7   a6
aaa_log-000595                    2     r      STARTED   7027691  21.7   a7
aaa_log-000598                    28    p      STARTED   7027815  21.7   a8
aaa_log-000599                    13    p      STARTED   7033090  21.7   a9

我正在尝试计算第 3 列(p 或 r)并按第 1 列分组

输出就像

Col1                   Count-P  Count-R
aaa_log-000592            3     3                                      
aaa_log-000595            0     1       
aaa_log-000598            1     0        
aaa_log-000599            1     0 

我在 awk 中找不到具有 group by 的 IF 条件的示例。

标签: awk

解决方案


awk(更具体地说,GNU 变体gawk)具有多维数组,可以使用输入值(包括您的示例中的字符串)进行索引。因此,您可以通过执行以您想要的方式计算值

{ 
    values[$3] = 1    # this line records the values in column three
    counts[$1][$3]++  # and this lines counts their frequency
}

第一行不是严格要求的,但它简化了生成输出的过程。

唯一剩下的部分是有一个END输出表格结果的子句。

END {
    # Print column headings
    printf "Col1              "
    for (v in values) {
        printf "  Count-%s", v
    }
    printf "\n"
      
    # Print tabulated results
    for (i in counts) {
        printf "%-20s", i
        for (v in values) {
            printf "    %d", counts[i][v]
        }
        printf "\n"
    }
}

生成values数组可以处理第三列的值可能未知的情况(例如,当您的输入中有错误时)。

如果您使用不同的awk实现(例如,您可能在 macOS 中找到的实现),数组索引可能会有所不同(例如,它们是一维数组,但由逗号分隔的索引列表索引)。这可能会增加一些额外的复杂性,但想法是一样的。

{
  files[$1] = 1
  values[$3] = 1
  counts[$1,$3]++
}

END {
    # Print column headings
    printf "Col1              "
    for (v in values) {
        printf "  Count-%s", v
    }
    printf "\n"

    # Print tabulated results
    for (f in files) {
        printf "%-20s", f
        for (v in values) {
            printf "    %d", counts[f,v]
        }
        printf "\n"
    }
}

推荐阅读