AWK 是 Unix/Linux 上诞生于 1970 年代的文本处理工具,名字取自三位作者 Aho、Weinberger、Kernighan 的姓氏首字母。它既不是一门独立的编程语言,也不是 sed 的替代品——它的核心能力在于 按行读取、按模式匹配、按字段处理结构化文本。1)
AWK 程序的骨架是:
''pattern { action }''
逐行扫描输入,当某行匹配 pattern 时执行对应的 action。省略 pattern 则每行都执行;省略 { action } 则等价于 { print }(打印整行)。
最简单的例子——打印文件每一行:
awk '{ print }' /etc/passwd
AWK 默认以空白(空格/Tab)分割每行为字段,用 $1、$2、… $NF 引用各字段。$0 代表整行。这是 AWK 区别于 sed 的核心特征——它能直接操作表格状数据。
打印第三列(比如 /etc/passwd 的用户 ID):
awk -F: '{ print $3 }' /etc/passwd
-F: 指定冒号为分隔符。也可以在内置变量 FS 中设置。
筛选行——只打印符合条件的行:
awk '$3 > 1000 { print $1, $3 }' /etc/passwd
统计——求某列的和/平均值:
awk '{ sum += $1 } END { print sum }' numbers.txt
格式化输出——用 printf 控制输出格式:
awk '{ printf "%-20s %s\n", $1, $3 }' data.txt
| 变量 | 含义 |
|---|---|
FS | 字段分隔符(默认空白) |
OFS | 输出字段分隔符(默认空格) |
RS | 记录分隔符(默认换行) |
ORS | 输出记录分隔符(默认换行) |
NR | 当前行号 |
NF | 当前行的字段数 |
$0 | 整行内容 |
$1..$NF | 各字段 |
改变 FS/OFS 即可在不同格式之间做转换。例如把 /etc/passwd 的冒号分隔转成 CSV:
awk 'BEGIN { FS=":"; OFS="," } { print $1, $3, $5 }' /etc/passwd
BEGIN 在第一行处理前执行,适合设置变量、打印表头。END 在所有行处理完后执行,适合输出汇总结果。
awk 'BEGIN { print "用户,ID" } { print $1 "," $3 } END { print "共" NR "行" }' FS=":" /etc/passwd
AWK 的数组是关联数组(类似 Python 的 dict),键可以是任何字符串。这是 AWK 处理分组统计的核心能力。
统计每个用户 Shell 的出现次数:
awk -F: '{ shells[$NF]++ } END { for (s in shells) print s, shells[s] }' /etc/passwd
这是 AWK 中最容易被忽略但极其强大的特性。当 RS=“”(空字符串)时,AWK 的分隔逻辑变为 按空行分块,每个块是一个「多行记录」。配合 FS 可处理段落式数据。2)
用 RS=“” 分块提取年龄:
awk 'BEGIN { RS=""; FS="\n" } { for (i=1; i<=NF; i++) if ($i ~ /年龄/) print $i }' data.txt
这个模式在处理日志分段、配置文件块、SQL 结果集时的效果远超逐行 grep。
统计 Web 日志中各 IP 的请求次数,按降序输出前 10:
awk '{ ips[$1]++ } END { for (ip in ips) print ips[ip], ip }' access.log | sort -rn | head -10