基于n列

时间:2017-08-18 07:40:13

标签: bash shell awk

这与我之前提出的问题[bash command for group by count

有关

如果我想概括一下该怎么办?例如 输入文件是

 ABC|1|2
 ABC|3|4
 BCD|7|2
 ABC|5|6
 BCD|3|5

输出应为

 ABC|9|12
 BCD|10|7

结果按组第一列计算并添加第二列和第三列的值,就像在SQL中使用group by命令类似。

我尝试修改链接中提供的命令但失败了。我不知道我是在犯一个概念上的错误还是一个愚蠢的错误,但我所知道的并不是所提到的命令都不起作用。

使用的命令

awk -F "|" '{arr[$1]+=$2} END arr2[$1]+=$5 END  {for (i in arr) {print i"|"arr[i]"|"arr2[i]}}' sample
awk -F "|" '{arr[$1]+=$2} END {arr2[$1]+=$5} END  {for (i in arr) {print i"|"arr[i]"|"arr2[i]}}' sample
 awk -F "|" '{arr[$1]+=$2 arr2[$1]+=$5} END  {for (i in arr2) {print i"|"arr[i]"|"arr2[i]}}' sample

此外,如果我在这里尝试的是限制使用仅将列总和为2。如果有n列并且我们想要执行诸如一列中的加法和另一列中的减法等操作会怎么样?如何进一步修改?

实施例

ABC|1|2|4|......... upto n columns
ABC|4|5|6|......... upto n columns
DEF|1|4|6|......... upto n columns

假设第一列需要总和,第二列需要平均值,第三列需要其他操作等。如何解决这个问题?

4 个答案:

答案 0 :(得分:2)

对于3个字段(键和2个数据字段):

$ awk '
BEGIN { FS=OFS="|" }      # set separators
{ 
    a[$1]+=$2             # sum second field to a hash
    b[$1]+=$3             # ... b hash
}
END {                     # in the end
    for(i in a)           # loop all
        print i,a[i],b[i] # and output
}' file
BCD|10|7
ABC|9|12

使用GNU awk的 n 列的更通用的解决方案:

$ awk '
BEGIN { FS=OFS="|" }
{
    for(i=2;i<=NF;i++)                    # loop all data fields
        a[$1][i]+=$i                      # sum them up to related cells
    a[$1][1]=i                            # set field count to first cell
}
END {
    for(i in a) {
        for((j=2)&&b="";j<a[i][1];j++)    # buffer output
            b=b (b==""?"":OFS)a[i][j]
        print i,b                         # output
    }
}' file
BCD|10|7
ABC|9|12

后期仅测试了2个字段(在会议中忙碌:)。

答案 1 :(得分:1)

awk -F\| '{ array[$1]="";for (i=1;i<=NF;i++) { arr[$1,i]+=$i }  } END { for (i in array) { printf "%s",i;for (p=2;p<=NF;p++) { printf "|%s",arr[i,p] } print "\n" } }' filename

我们使用两个数组,(array和arr)数组是一个跟踪所有第一部分的单维数组,而arr是一个多维数组,键入第一部分然后是片段索引,例如arr [“ABC”, 1] = 1和arr [“ABC”,2] = 2。最后我们循环遍历数组,然后遍历数据集中的每个字段,我们从多维数组arr中提取数据。

答案 2 :(得分:1)

使用多维数组的

gawk 方法:

awk 'BEGIN{ FS=OFS="|" }{ a[$1]["f2"]+=$2; a[$1]["f3"]+=$3 }
     END{ for(i in a) print i,a[i]["f2"],a[i]["f3"] }' file
  • a[$1]["f2"]+=$2 - 总结第二个字段的值(f2 - 字段2)

  • a[$1]["f3"]+=$3 - 总结第3个字段的值(f3 - 字段3)

输出:

ABC|9|12
BCD|10|7

其他短 datamash 解决方案(将提供相同的输出):

datamash -st\| -g1 sum 2 sum 3 <file
  • -s - 对输入行进行排序

  • -t\| - 字段分隔符

  • sum 2 sum 3 - 分别汇总第2和第3个字段的值

答案 3 :(得分:1)

这将在任何awk中工作,并将在输出中保留输入键顺序:

$ cat tst.awk
BEGIN { FS=OFS="|" }
!seen[$1]++ { keys[++numKeys] = $1 }
{
    for (i=2;i<=NF;i++) {
        sum[$1,i] += $i
    }
}
END {
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s%s", key, OFS
        for (i=2;i<=NF;i++) {
            printf "%s%s", sum[key,i], (i<NF?OFS:ORS)
        }
    }
}

$ awk -f tst.awk file
ABC|9|12
BCD|10|7