我有一个这样的文件:
A 100
A 200
A 300 #sum=600
B 400
B 500 #sum=900
A 600
A 700
A 800 #sum=2100
我希望输出是:
A 600
B 900
A 2100
C sum_of_C
D sum_of_D
我可以用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
awk -f awkscript file
没有成功。解决办法是什么?
答案1
我不完全确定你if
想在那里做什么。NR
是记录数;用于NF
字段数量(如果这是您的目标)。你不能把{}
方块放在这样的东西中间。
我认为您的目标是将这一行中的字段值与前一行中的字段值进行比较,当我们到达新的数据“组”时打印出总和。如果是这样的话,这个脚本将执行您想要的操作,并且我认为与您的目标几乎相同:
{
if (last && $1 != last) {
print last, sum
sum = 0
}
sum = sum + $2
last = $1
}
END {
print last, sum
}
我们创建一个新变量来保存上一行last
第一个字段 ( ) 的值。$1
我们将用它来跟踪我们正在查看的组。
- 对于每一行(因为我们
{ ... }
在顶层),我们首先测试 a) 是否last
设置(因为我们不想在第一行打印任何内容),并且 b) 第一个字段的值不同于last
。如果是,我们打印出 的值last
、一个空格(因为,
)以及sum
我们计算出的 。 (如果您想要一个制表符,请"\t"
像您一样在引号中使用) - 打印后,我们重置
sum
为零。 $2
无论哪种方式,我们都将第二个字段 ( )的值添加到sum
。- 对于每一行,我们将第一个字段(我们的组)保存到 中
last
,以便我们可以使用它在下一行进行比较。 - 最后,我们还想打印最后一组。为此,我们使用一个
END { ... }
块。当我们用完数据时,它会在程序结束时运行。我们像以前一样打印出总和以及我们正在合作的组。
如果我运行:
awk -f sum.awk < data
通过您的数据文件,我得到以下输出:
A 600
B 900
A 2100
如预期的。
有更简单的方法可以做到这一点,无论是在 awk 中还是其他方式。特别是,我们可以将上面的主体替换为:
last && $1 != last {
print last, sum
sum = 0
}
{
sum = sum + $2
last = $1
}
这里我们使用 awk 的条件块语法而不是显式if
测试:该程序的行为与上面的相同,但更惯用。在这个例子中并没有太大的不同,但是了解您是否正在学习 awk 是很有用的。
#sum=
如果您给出的文件示例确实是带有行(或类似内容)的文件示例,那么您可以使用以下脚本:
{
sum = sum + $2
if (NF == 3) {
print $1, sum
sum = 0
}
}
对于每一行,这会将第二个字段的值添加到sum
变量中。在恰好包含三个字段 ( NF == 3
) 的行上,我们打印出总计,并重置sum
为零。
答案2
如果您的文件足够小,可以将所有总和放入内存中,您可以执行以下简单操作:
$ awk '{sum[$1]+=$2}END{for(pat in sum){print pat,sum[pat]}}' file
A 2700
B 900
这与注释脚本相同awk
:
#!/usr/bin/awk -f
{
## Here, we use $1 as the key of an associative array
## and increment its current value by $2. The result of
## this will be an array element for each different $1 in
## the file whose value will be the sum of all associated $2s.
sum[$1]+=$2
}
## The END{} block is exacuted after the entire file
## has been processed.
END{
## Iterate through the keys of the array (the $1s),
## saving each as 'pat'. Then, print the current value of
## 'pat' as well as the associated value (the sum) from
## the array.
for(pat in sum){
print pat,sum[pat]
}
}
这种方法唯一可能出现的问题是,如果您有太多行,则保留 s 数组$1
将导致内存不足。这在现代系统上不太可能发生。另一方面,当文件的行不按顺序排列时,此方法也适用,因为它可以处理未排序的文件。