日志要按列提取、统计报表要算总和、两个文件要按关键字关联——用 grep 只能整行过滤,用 awk 才能按字段切分、计算、重组输出。awk 是 Linux 文本处理三剑客(grep、sed、awk)里功能最强大的一个,本质是一门小型编程语言。这篇文章从最常用的字段操作讲起,带你快速上手 awk 的实战用法。
一、awk 核心概念:按字段处理
awk 默认按空白(空格/Tab)把每一行拆成多个字段,$1 是第一个字段、$2 是第二个、$0 是整行:
awk '{print $1}' /var/log/nginx/access.log # 打印每行第一个字段(IP)
awk '{print $1, $9}' access.log # 打印 IP 和状态码
awk '{print $0}' access.log # 打印整行(等价于 cat)
比如 Nginx 日志行 192.168.1.1 - - [18/Sep/2026:10:00:00] "GET / HTTP/1.1" 200 1234,$1 是 IP、$9 是状态码、$10 是响应字节数。
指定分隔符:字段默认按空白切分,用 -F 可以改成任意字符:
awk -F: '{print $1}' /etc/passwd # 按冒号切分,取用户名
awk -F'[" "]' '{print $6}' access.log # 多分隔符,提取请求方法
awk -F, '{print $2}' data.csv # 处理 CSV 文件
二、常用内建变量
| 变量 | 含义 |
|---|---|
$0 |
整行内容 |
$1~$N |
第 N 个字段 |
NF |
当前行的字段总数 |
NR |
已处理的行号(从 1 开始) |
FS |
输入分隔符(同 -F) |
OFS |
输出分隔符,默认空格 |
BEGIN |
开始处理前执行一次 |
END |
全部处理完后执行一次 |
awk '{print NF}' file # 每行有几个字段
awk 'NR==1' file # 打印第一行
awk '{print NR, $0}' file # 带行号输出
awk 'BEGIN{OFS="--"}{print $1, $2}' file # 自定义输出分隔符
三、条件过滤:比 grep 更灵活
awk 支持在花括号前加条件,只处理符合条件的行:
awk '$9 == 500' access.log # 只输出状态码 500 的行
awk '$9 >= 500 {print $1, $9, $7}' access.log # 5xx 错误,输出 IP+状态码+URL
awk '$10 > 100000 {print $1, $10}' access.log # 响应超过 100KB 的请求
awk '/error|exception/ {print NR, $0}' app.log # 正则匹配
awk 'NR > 1 && NR <= 10' file # 输出第 2 到 10 行
awk '$1 != "127.0.0.1"' access.log # 排除指定 IP
支持 ==、!=、>、<、>=、<=、&&、||、!,以及正则 /pattern/。
四、实战场景
1. 统计日志里的状态码分布
awk '{count[$9]++} END {for (code in count) print code, count[code]}' access.log
按状态码分组计数,输出形如 200 15320、404 321 的结果。
2. 计算平均响应时间 / 求和
awk '{sum += $10} END {print "总流量:", sum/1024/1024, "MB"}' access.log
awk '{sum += $10; n++} END {print "平均字节数:", sum/n}' access.log
3. 提取并去重 IP 列表
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head
排在最上面的就是访问量最高的 IP,配合 awk '$1 > 100' 可快速发现异常刷量。
4. 分析 /etc/passwd 用户
awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd # 找出普通用户(UID>=1000)
awk -F: '{print $1, $7}' /etc/passwd # 用户名和登录 Shell
5. 报表生成:计算每台服务器的错误数
awk '{if ($9 >= 500) err[$1]++} END {for (ip in err) print ip, err[ip]}' access.log
6. 文件间关联(类似 join)
awk 'NR==FNR {name[$1]=$2; next} {print $1, name[$1]}' id_name.txt data.txt
先读第一个文件建映射,再处理第二个文件按 key 关联,常用于合并两个列表。
五、进阶:printf 格式化输出
awk '{printf "%-15s %s\n", $1, $9}' access.log # 左对齐 15 位
awk '{printf "%.2f MB\n", $10/1024/1024}' access.log # 保留两位小数
awk 'BEGIN{printf "%-8s %-6s\n", "状态码", "数量"}'
写报表、对齐列输出时 printf 比 print 好用得多。
六、常见坑与建议
- 花括号位置:
awk '条件 {动作}',条件在外面、动作在花括号里,两者都写反了就是语法错误; - 变量默认是字符串:
$9 == 500时 awk 会自动转数值比较,但要小心带引号的比较$9 == "500"是字符串比较,行为不同; - 大文件:awk 处理 GB 级日志没问题,但
END里累加太多键(如海量 IP)会占内存,可以用sort | uniq -c分流; - 单引号转义:awk 脚本整体用单引号包裹,脚本内想用单引号(如字符 ' ')比较麻烦,必要时改用双引号包外层并转义。
总结:awk 一句话概括就是"按列处理文本"。入门记住三条——$1 取字段、-F 定分隔符、条件 {动作} 过滤,再配合 BEGIN/END 做统计,日志分析、报表计算、文件关联这些活儿都能轻松拿下。比起 grep 只能"整行过滤",awk 能"拆开重组",是运维必会的第二把文本刀。




