awk 从入门到进阶(中)

前言

在现代数据驱动的场景中,文本数据的处理与分析已成为系统管理、数据分析和开发工作中不可或缺的一部分。从服务器日志的实时解析到大规模数据集的清洗与统计,从配置文件调整到自动化报告生成,高效的文本处理能力直接决定了任务的完成效率与成果质量。作为一款内置于操作系统的文本处理利器,awk 不仅能轻松应对日志分析、数据过滤和列操作,还能在数值计算、条件筛选和数据聚合等复杂任务中大显身手。

如果说基础篇为你打开了 awk 的大门,那么本篇(中篇)将带你深入探索其核心功能。我们将聚焦于以下内容:

  • 数值计算:从浮点运算到逐行统计,展示 awk 在数据处理中的灵活性。
  • if 语句:通过条件判断实现精准筛选,结合正则表达式完成复杂逻辑。
  • for 循环:遍历字段或执行聚合操作,处理多维度数据。
  • while 循环:动态控制流程,适应更复杂的处理需求。
  • 综合应用:编写数据分析脚本,汇总和处理大规模数据。

从简单的运算到复杂的逻辑控制,我们将逐步解锁 awk 的强大潜力,让你在文本处理和数据分析的道路上更进一步。让我们开始这场从基础到进阶的探索之旅吧!


计算:从简单运算到数据统计

awk 的计算能力是其核心优势之一。无论是简单的数学运算还是大规模数据的统计分析,awk 都能以高效的方式完成任务。以下从基础运算入手,逐步扩展到按行计算和列值累加。

支持浮点数运算

与 Shell 脚本默认仅支持整数运算不同,awk 天生支持浮点数计算,使其在需要精确结果的场景中表现卓越。例如:

awk 'BEGIN {print 10/3}'

运行后输出 3.3333333333333335。相比之下,Shell 中的 $((10/3)) 仅返回整数 3,而 awk 的浮点运算能力显然更适合财务计算、科学数据分析等场景。

BEGIN 块的使用还使得这条命令无需输入文件即可运行,体现了 awk 在独立计算中的灵活性。无论是加减乘除还是内置数学函数(如 sqrt()sin()),awk 都能轻松胜任。

按行计算

在实际工作中,我们常需对文件的每一行进行计算。例如,假设文件 data.txt 内容如下:

item1 10 20 30
item2 15 25 35

计算每行第 3、4、5 列的总和并输出:

awk '{sum = $3 + $4 + $5; print $0, sum, sum/3}' data.txt

输出:

item1 10 20 30 80 26.6667
item2 15 25 35 75 25

执行逻辑:

  • sum = $3 + $4 + $5:计算第 3、4、5 列的和,存入变量 sum
  • print $0, sum, sum/3:打印整行、总和及平均值。
  • $0 表示当前行完整内容,字段默认以空格分隔。

这种按行计算非常适合处理结构化数据,如统计日志响应时间或计算 CSV 文件数值列。

累加列值

当需要全局统计某列时,awk 的累加特性大放异彩。例如,计算所有行第 1 列的总和:

awk '{total += $1} END {print total}' data.txt

假设 data.txt 为:

5  apple  10
3  banana 20
8  orange 15

输出:

16

解析:

  • {total += $1}:每行将第 1 列累加到 total,未初始化时默认为 0。
  • END {print total}:处理完所有行后输出结果。

此方法适用于统计错误次数、销售总额等场景。多列累加只需增加变量:

awk '{sum1 += $1; sum2 += $2} END {print sum1, sum2}' data.txt

if 语句:灵活的条件控制

条件判断是编程的核心逻辑,awk 提供类似 C 语言的 if 语句,结合模式匹配能力,使其在文本处理中更智能。

基本语法

if 语句格式:

if (condition) {
    
    
    action
}
  • condition:条件表达式,如比较运算($1 > 10)、逻辑运算($1 > 0 && $2 < 100)或正则匹配($0 ~ /error/)。
  • action:条件为真时执行的操作。

单语句省略大括号

若只有一条语句,可省略 {}

if (condition) action

例如:

awk '{if ($2 > 80) print $0}' data.txt

等价于:

awk '$2 > 80 {print $0}' data.txt

示例 1:筛选高值行

假设 data.txt 为:

item1 85 10
item2 75 20
item3 90 15

运行:

awk '$2 > 80 {print $0}' data.txt

输出:

item1 85 10
item3 90 15

示例 2:if-else 语句

分支逻辑示例:

awk '{if ($2 > 80) print "High"; else print "Low"}' data.txt

输出:

High
Low
High

多语句需用大括号:

awk '{if ($2 > 80) {print "High"; print $0} else {print "Low"; print $0}}' data.txt

输出:

High
item1 85 10
Low
item2 75 20
High
item3 90 15

注意事项

  1. 多语句需大括号
    省略大括号会导致逻辑错误,如:

    awk '{if ($2 > 80) print "High"; print $0}'  # 错误
    
  2. 嵌套 if
    示例:

    awk '{if ($1 > 50) {if ($2 > 80) print $0}}'
    
  3. 可读性
    复杂脚本中保留大括号提升维护性。


配合正则表达式:复杂匹配的利器

awk 的模式匹配与条件判断结合,借助正则表达式实现强大筛选功能。

示例 1:筛选特定模式

筛选以 - 开头且第 2 列大于 80 的行:

awk '/^-/ && $2 > 80 {print $0}' data.txt

data.txt

-item1 85 10
item2 75 20
-item3 90 15

输出:

-item1 85 10
-item3 90 15

示例 2:排除模式

排除含 “asd” 的行:

awk '!/asd/' data.txt

等价于:

awk '{if ($0 !~ /asd/) print $0}' data.txt

示例 3:复杂逻辑

标记高低值:

awk '/^-/ {if ($2 > 80) print "High: "$0; else print "Low: "$0}' data.txt

输出:

High: -item1 85 10
High: -item3 90 15

for 循环:遍历与聚合

for 循环类似 C 语言,适合遍历字段或聚合数据。

基本语法

for (init; condition; increment) {
    
    
    action
}

示例 1:遍历字段

打印每行所有字段:

awk '{for (i = 1; i <= NF; i++) print $i}' data.txt

输出:

-item1
85
10
item2
75
20
-item3
90
15

示例 2:奇数列

打印奇数列:

awk '{for (i = 1; i <= NF; i += 2) printf $i " "} {print ""}' data.txt

输出:

-item1 10 
item2 20 
-item3 15 

示例 3:列总和

计算每行总和:

awk '{sum = 0; for (i = 1; i <= NF; i++) sum += $i; print sum}' data.txt

data.txt

1 2 3
10 20 30

输出:

6
60

while 循环:动态流程控制

while 循环为 awk 提供了动态控制能力,特别适合处理不确定次数的迭代或外部输入。

基本语法

while (condition) {
    
    
    action
}
  • condition:每次循环前检查,若为真则执行。
  • action:循环体内操作。

示例 1:累加到阈值

累加第 1 列直到超过 10:

awk '{sum = 0; while (sum <= 10) {sum += $1; print sum}}' data.txt

data.txt

3  apple
4  banana
5  orange

输出:

3
7
12

解析:

  • sum += $1:每次加第 1 列。
  • sum <= 10:条件控制循环。

示例 2:结合 getline

从外部命令读取数据:

awk 'BEGIN {while ("whoami" | getline) print $0}'

输出当前用户名,getline 从管道读取每次一行,直到结束。

示例 3:遍历字段直到条件

打印字段直到遇到负数:

awk '{i = 1; while (i <= NF && $i >= 0) {print $i; i++}}' data.txt

data.txt

5 10 -3 20
2 8 15 4

输出:

5
10
2
8
15
4

解析:

  • i <= NF && $i >= 0:字段序号不超过总数且值非负。
  • i++:递增索引。

注意事项

  1. 无限循环风险
    确保条件最终为假,否则需用 break 跳出:

    awk 'BEGIN {i = 0; while (i < 5) {print i; i++; if (i == 3) break}}'
    
  2. for 对比
    for 适合已知次数迭代,while 适合动态条件。


小结

本篇深入探索了 awk 的计算、条件判断、循环控制(forwhile)及正则表达式应用,展示了其在文本处理中的强大能力。主要内容包括:

  • 计算:支持浮点运算、逐行计算和列值累加。
  • if 语句:灵活条件判断,单语句可省大括号。
  • 正则表达式:结合模式匹配实现复杂筛选。
  • for 循环:遍历字段和聚合数据。
  • while 循环:动态控制流程,处理不确定迭代。

这些技能让你能高效应对从简单筛选到复杂分析的任务,为后续高级应用打下基础。下一阶段将聚焦脚本编写与大规模数据处理,敬请期待!