前言
经过前面几节的学习,我们对 awk 的基础功能以及 awk 语言有了一定的认知,虽然前面有很大一部分属于理论的东西,l老是让我看理论,
从这节开始,我们将更加深入的学习 awk。
Awk 最初的设计目标是用于日常的数据处理, 例如信息查询, 数据验证, 以及数据转换与归约,所以这节我们将来学习 awk 的数据处理,利用前面学习的知识实现更加强大的功能。
数据转换与归约
Awk 最常用的一个功能是把数据从一种形式转换成另一种形式, 通常情况下, 是把一种程序的输出格式, 转换成另一种程序要求的格式. 另一个常用的功能是从一个大数据集中提取相关的数据,例如下面的例子:
列求和
需求:每一个输入行都含有若干个字段, 每一个字段都包含数字, 程序的任务是计算每一列的和, 而不管该行有多少列。
思路:要求每列的和,一定是需要一个数组来储存和,又因为每列的字段数不一定,因此到底要计算多少次加和或者说记录处理多少个字段,需要一个变量来记录最大的字段数
有了上面的思路,程序也就不那么难了,看代码
awk '{
for (i = 1; i < NF; i++) {
sum[i] += $i
}
# 记录最长的字段
if (maxFieldCount < NF) {
maxFieldCount = NF
}
}
END {
for (i = 1; i < maxFieldCount; i++ ) {
printf("%g", sum[i])
if (i < maxFieldCount) {
printf("\t")
} else {
printf("\n")
}
}
}' $*
假设某些字段不是数值型, 所以它们不能被计算在内。策略是新增一个数组 numcol,用于跟踪数值型字段, 函数 isnum 用于检查某项是否是一个数值, 由于用到了函数, 所以测试只需要在一个地方完成, 这样做有助于将来对程序进行修改。如果程序足够相信它的输入, 那么只需要查看第 1 行就够了, 我们仍然需要记录字段数, 因为在 END 中, NF 的值是零。
sum.awk
#!/usr/bin/bash
awk 'NR == 1 { fieldCount = NF;
for (i = 1; i <= NF; i++) {
numcol[i] = isnum($i)
}
}
{
for (i = 1; i <= NF; i++) {
if (numcol[i]) {
sum[i] += $i
}
}
}
function isnum(n) { return n ~ /^[+-]?[0-9]+$/}
END { for (i = 1; i < fieldCount; i++) {
if (numcol[i]) {
printf("%g",sum[i])
} else {
printf("--")
}
printf(i < nfld ? "\t" : "\n")
}
}' $*