Shell 四剑客之三:awk 文本处理实战

awk 是按列处理文本的利器:日志统计、报表生成、字段提取都靠它。它把每一行按分隔符切成字段,$1、$2 随取随用,还能求和计数。这篇讲 awk 的基本结构、字段提取、统计和日志分析实战。

一、基本结构

# 模式 {动作}:匹配的行执行动作
awk '/ERROR/ {print $0}' app.log

# 常用内置变量
# $0 整行,$1 第 1 列,$2 第 2 列,NF 列数,NR 行号
# -F 指定分隔符,BEGIN 开始前执行,END 结束后执行
awk -F: '{print $1, $3}' /etc/passwd   # 冒号分隔,取用户名和 UID
awk '{print NR, $0}' file.txt          # 每行前面加行号

记住三个变量就够入门:$0 是整行,$N 是第 N 列,NF 是这行有几列。分隔符默认是空白,冒号、逗号用 -F 指定。

二、字段提取与格式化

# 取第 1 列和第 3 列,逗号分隔
awk '{print $1, $3}' data.txt

# printf 格式化输出,对齐成表格
awk '{printf "%-15s %8d\n", $1, $2}' data.txt

# 拼接字段
awk '{print $2 "@" $1}' users.txt

# 只打印最后一列(NF 是列数,$NF 就是最后一列)
awk '{print $NF}' data.txt

# 逗号分隔的 CSV,取第 2 列
awk -F, '{print $2}' data.csv

三、统计:求和、计数、平均

# 第 2 列求和
awk '{sum += $2} END {print sum}' data.txt

# 求平均
awk '{sum += $2; n++} END {print sum / n}' data.txt

# 计数:每种状态各出现几次
awk '{count[$1]++} END {for (k in count) print k, count[k]}' status.txt

# 找最大值所在的行
awk '$3 > max {max = $3; line = $0} END {print line}' data.txt

END {} 是统计的关键:处理过程中累加,结束后一次性输出结果。数组 count[$1]++ 是 awk 的招牌写法,按某个字段分组计数一行搞定。

四、条件与关联数组

# 只处理第 3 列大于 100 的行
awk '$3 > 100 {print $0}' data.txt

# if-else:按数值分档
awk '{if ($2 >= 90) print $1, "优秀"; else if ($2 >= 60) print $1, "及格"; else print $1, "不及格"}' score.txt

# 关联数组:按 IP 统计请求数,再按次数排序
awk '{ip[$1]++} END {for (k in ip) print ip[k], k}' access.log | sort -nr | head

五、实战:日志分析

# 统计各状态码出现次数(假设第 9 列是状态码)
awk '{code[$9]++} END {for (k in code) print k, code[k]}' access.log | sort -nr

# 统计访问量 Top 10 的 IP
awk '{ip[$1]++} END {for (k in ip) print ip[k], k}' access.log | sort -nr | head -10

# 算平均响应时间(假设第 10 列是耗时,单位毫秒)
awk '{sum += $10; n++} END {print "平均耗时:", sum / n "ms"}' access.log

# 找慢请求:耗时超过 1000ms 的行
awk '$10 > 1000 {print $0}' access.log | head -20

awk 的精髓是“按列思考”:先想清楚你要第几列,再想对它做什么。日志分析、报表统计、字段提取,这三类活 awk 一行就能干,别急着写 Python。

发表回复

后才能评论