使用 AWK 在块中求和(模式改变时重新开始求和)

Ook*_*ker 5 awk

我有一个这样的文件:

A 100
A 200
A 300 #sum=600
B 400
B 500 #sum=900
A 600
A 700
A 800 #sum=2100
Run Code Online (Sandbox Code Playgroud)

我希望输出是:

A 600
B 900
A 2100
C sum_of_C
D sum_of_D
Run Code Online (Sandbox Code Playgroud)

我可以用for, sed,grep和来做到这一点awk

但是因为我正在学习awk,我想写一个awk脚本。到目前为止,我有:

if (${NR {print $1}} == ${NR-1 {print $1}}) 
  sum+=$2
  print $0"\t"sum
else
  sum=$2
  print $0"\t"sum
Run Code Online (Sandbox Code Playgroud)

awk -f awkscript file没有成功。解决办法是什么?

Mic*_*mer 6

我不完全确定你if想在那里做什么。NR是记录数;使用NF的字段的数量,如果这是你的目标是什么了。你不能把{}块放在这样的东西中间。

我认为您的目标是将这一行中的一个字段的值与前一行中的一个字段的值进行比较,当我们到达一个新的“组”数据时打印出总和。如果是这样的话,这个脚本会做你想做的,我认为几乎等同于你的目标:

{
    if (last && $1 != last) {
        print last, sum
        sum = 0
    }
    sum = sum + $2
    last = $1
}
END {
    print last, sum
}
Run Code Online (Sandbox Code Playgroud)

我们创建了一个新变量last来保存$1上一行第一个字段 ( )的值。我们将使用它来跟踪我们正在查看的组。

  • 对于每一行(因为我们{ ... }在顶层),我们首先测试是否last设置了 a)(因为我们不想在第一行打印任何内容),以及 b)第一个字段的值是否不同于last. 如果是,我们打印出 的值last,一个空格(因为,),以及sum我们计算出来的。(如果你想要一个标签,"\t"像你一样使用引号)
  • 打印后,我们重置sum为零。
  • 无论哪种方式,我们都将第二个字段 ( $2)的值添加到sum
  • 对于每一行,我们将第一个字段(我们的组)保存到 中last,以便我们可以在下一行中使用它进行比较。
  • 最后,我们还想打印出最后一组。为此,我们使用一个END { ... }块。当我们用完数据时,它会在程序结束时运行。我们像以前一样打印出总和和我们正在合作的组。

如果我运行:

awk -f sum.awk < data
Run Code Online (Sandbox Code Playgroud)

使用您的数据文件,我得到以下输出:

A 600
B 900
A 2100
Run Code Online (Sandbox Code Playgroud)

如预期的。


有更简单的方法可以做到这一点,无论是 awk 还是其他方式。特别是,我们可以将上面的 body 替换为:

last && $1 != last {
    print last, sum
    sum = 0
}
{
    sum = sum + $2
    last = $1
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们使用 awk 的条件块语法而不是显式if测试:该程序的行为与上面的相同,但更符合习惯。在这个例子中并没有太大的不同,但是了解你是否正在学习 awk 很有用。


如果您提供的文件示例字面意思是带有#sum=行(或类似内容),则可以使用此脚本:

{
    sum = sum + $2
    if (NF == 3) {
        print $1, sum
        sum = 0
    }
}
Run Code Online (Sandbox Code Playgroud)

对于每一行,这会将第二个字段的值添加到sum变量中。在正好有三个字段 ( NF == 3) 的行上,我们打印出我们的总数,并重置sum为零。