awk 是什么
awk 是一门面向字段的行处理语言,结构是「模式 { 动作 }」:对每一行判断模式是否成立,成立就执行动作。它自带变量系统——$0 是整行,$1 到 $NF 是各个字段,NR 是当前行号,NF 是字段数,FS/OFS 控制输入输出分隔符。相比 cut 只会按位置切分、sed 只能做替换,awk 能直接做条件过滤、数学计算与分组聚合,因此是统计日志、生成报表的主力工具。
基本信息
| 适用平台 | Linux 与 macOS 通用;Linux 上通常是 gawk 或 mawk,功能有差异(如 gawk 的 gensub、asort 在 mawk 中不可用) |
|---|---|
| 命令语法 | awk [选项] '模式{动作}' [文件...];不写模式表示每行都执行,不写动作默认等价于 print $0 |
| 内建变量 | $0 整行、$N 第 N 字段、NF 字段数、NR 累计行号、FNR 当前文件行号、FS 输入分隔符、OFS 输出分隔符、FILENAME 当前文件名 |
| 常用选项 | -F 指定字段分隔符、-v 传入外部变量(在做解析之前赋值)、-f 从文件读脚本 |
| 程序结构 | BEGIN 在处理前执行一次、END 在结束后执行一次,常用来打印表头与汇总结果 |
典型使用场景
- 抽取列:从命令输出或日志里只取需要的字段,等价于 cut 但更灵活
- 条件过滤:按数值阈值筛选,例如找出响应时间超过 1 秒的记录
- 汇总统计:对某一列求和、求平均、计数,END 块里输出结果
- 分组聚合:以某个字段为键累加,输出各分组的合计
- 格式化输出:用 printf 对齐列宽,生成便于阅读的报表
- 处理非标准分隔:用 -F 处理以冒号、逗号或竖线分隔的数据
常用示例
常用示例
awk '{print $1, $3}' data.txt
awk -F: '{print $1}' /etc/passwd # 冒号分隔取用户名
awk -F: '$3>=1000 {print $1, $3}' /etc/passwd # 过滤普通用户
awk 'NR>1 && $3>100' data.txt # 跳过表头并过滤
awk 'NR==1 || /ERROR/' app.log # 首行或含 ERROR 的行
awk '{sum+=$5} END {print "total", sum}' # 对第 5 列求和
awk -F, '{c[$1]+=$2} END {for (k in c) print k, c[k]}' sales.csv # 按第 1 列分组求和
head -1 f.csv && awk -F, 'NR>1 {n++; s+=$3} END {printf "avg=%.2f\n", s/n}' f.csv内建变量速查
| 变量 | 含义 | 注意 |
|---|---|---|
| $0 / $N | 整行 / 第 N 个字段 | 字段赋值会触发整行重建($0 重新拼接) |
| NF | 当前行的字段数 | $NF 是最后一个字段,取末列常用 |
| NR / FNR | 累计行号 / 当前文件内的行号 | 多文件处理时用 FNR 才不会串号 |
| FS / OFS | 输入分隔符 / 输出分隔符 | FS 用 -F 或 BEGIN 里赋值 |
| FILENAME | 当前正在处理的文件名 | 常用于在输出里标注数据来源 |
默认的字段分隔是「连续空白折叠成一个」,所以对齐良好的表格能直接按列取值;用 -F 指定分隔符时不做折叠,例如 -F, 遇到连续的逗号会产生空字段,处理 CSV 里的空列时要留意。
向脚本传外部值必须用 -v(例如 awk -v limit=100 '$3>limit'),它会在 BEGIN 之前赋值;直接在脚本里写 shell 变量会因为引号关系取不到值。反过来,需要 shell 展开的内容应放在单引号之外或用双引号包脚本,但要清楚哪些会被 shell 先处理。
awk 的比较有自动类型转换规则:$3 > 100 是数值比较,而 $3 == "100" 是字符串比较,字段若含前导空格或单位,结果可能出乎意料。处理数值前先用 $3 + 0 强制转数,可以避免大量静默错误。
实现差异要看清楚:Linux 上常见的实现有 gawk 与 mawk,gawk 提供 gensub(带捕获组的替换)、asort(数组排序)以及较新版本的 --csv 模式等扩展,mawk 只实现 POSIX 子集且速度更快。脚本依赖扩展特性前,先在目标机器执行 awk --version 确认实现与版本。