
在 Linux 文本处理中,`awk` 常用于从日志、配置、统计结果或命令输出中提取指定字段。与单纯按关键字过滤不同,`awk` 更关注“行”和“列”的结构:每一行是一条记录,每一列是一个字段,默认按空白字符切分,也可以通过 `-F` 指定逗号、冒号、竖线等分隔符。掌握 `awk` 时,应先理解字段编号,再明确分隔符,随后选择要输出的字段,并结合行号、条件表达式、格式化输出或汇总逻辑完成实际处理。按照这个顺序使用,`awk` 就能从简单的列提取扩展到日志分析和数据整理。
`awk` 的基础模型是按行读取文本,再把每一行拆成字段。`$0` 表示整行,`$1` 表示第 1 个字段,`$2` 表示第 2 个字段,以此类推。
在未指定分隔符时,`awk` 默认使用空格或制表符切分字段。
# 查看示例文件内容,确认每一列代表的含义$ cat users.txtalice app 18bob db 42carol cache 7# 提取第 1 列和第 3 列$ awk '{print $1, $3}' users.txtalice 18bob 42carol 7
上例中,`users.txt` 的第 1 列是用户名,第 2 列是服务名,第 3 列是数值。`awk '{print $1, $3}'` 只输出第 1 列和第 3 列。
如果文本不是按空白字符分隔,就需要通过 `-F` 指定字段分隔符。常见分隔符包括逗号、冒号、竖线和制表符。
CSV 文件通常使用逗号分隔字段,此时如果仍按默认空白切分,`awk` 无法正确识别列。
# 查看逗号分隔的 CSV 内容$ cat users.csvalice,app,18bob,db,42carol,cache,7# 使用 -F 指定逗号为字段分隔符$ awk -F, '{print $1, $3}' users.csvalice 18bob 42carol 7
`-F,` 表示把逗号作为分隔符。对于 `/etc/passwd` 这类冒号分隔文件,可以使用 `-F:` 处理。
• 分隔符决定字段如何切分,字段编号决定输出哪一列。
• 如果结果不符合预期,应先检查分隔符,而不是直接修改字段编号。
字段切分正确后,下一步是确定输出内容。可以输出整行,也可以输出单个字段、多个字段,或给字段增加固定文本。
`$0` 表示当前完整行,适合在调试阶段确认 `awk` 实际读取到了哪些内容。
# 输出整行内容,观察 $0 和字段编号的关系$ awk '{print $0}' users.txtalice app 18bob db 42carol cache 7# 同时输出整行和第 2 列$ awk '{print $0, "service=" $2}' users.txtalice app 18 service=appbob db 42 service=dbcarol cache 7 service=cache
多个字段可以按任意顺序输出,也可以在输出中加入固定文本,使结果更容易阅读。
# 调整字段顺序,先输出服务名,再输出用户名$ awk '{print $2, $1}' users.txtapp alicedb bobcache carol# 给字段增加固定文本说明$ awk '{print "user=" $1, "count=" $3}' users.txtuser=alice count=18user=bob count=42user=carol count=7
字段顺序不必和原文本保持一致。只要字段编号明确,就可以根据需要重新组织输出结果。
实际排查中,通常并不是所有行都需要输出。`awk` 可以通过 `NR` 控制行号范围,也可以通过字段条件筛选记录。
`NR` 表示当前处理到的行号,适合提取文件中的指定行或某个行号范围。
# 使用 NR 只提取第 2 行$ awk 'NR==2 {print $1, $2, $3}' users.txtbob db 42# 使用 NR 提取第 2 行到第 3 行$ awk 'NR>=2 && NR<=3 {print $1, $3}' users.txtbob 42carol 7
字段可以参与数值比较和字符串比较。数值比较适合处理容量、次数、耗时等列,字符串比较适合处理状态、类型或服务名。
# 提取第 3 列大于 10 的记录$ awk '$3 > 10 {print $1, $2, $3}' users.txtalice app 18bob db 42# 同时匹配服务名和数值条件$ awk '$2 == "db" && $3 > 20 {print $1, $3}' users.txtbob 42
条件表达式写在动作前面,只有满足条件的行才会执行 `{print ...}` 中的输出动作。
当输出需要对齐、添加标签或计算汇总结果时,可以使用 `printf`、变量和 `END` 代码块。
`print` 适合快速查看结果,`printf` 适合控制列宽、换行和输出格式。
# 使用 printf 控制输出列宽$ awk '{printf "%-8s %-8s %5d\n", $1, $2, $3}' users.txtalice app 18bob db 42carol cache 7# 输出更适合阅读的键值格式$ awk '{printf "user=%s service=%s count=%d\n", $1, $2, $3}' users.txtuser=alice service=app count=18user=bob service=db count=42user=carol service=cache count=7
`awk` 可以在处理每一行时累加字段值,并在 `END` 阶段输出最终结果。
# 汇总第 3 列的数值$ awk '{sum += $3} END {print sum}' users.txt67# 输出平均值,NR 表示已处理的行数$ awk '{sum += $3} END {print sum / NR}' users.txt22.3333
`END` 只在所有行处理完成后执行一次,适合输出总数、平均值或最终统计结果。
以访问日志为例,如果每行依次记录 IP、请求方法、路径、状态码和耗时,就可以通过字段条件快速提取异常请求。
# 查看访问日志中的关键字段$ cat access.log10.0.0.1 GET /index.html 200 1210.0.0.2 POST /api/login 500 8310.0.0.3 GET /health 200 3# 提取状态码大于等于 500 的 IP、路径和耗时$ awk '$4 >= 500 {print $1, $3, $5}' access.log10.0.0.2 /api/login 83
该命令以第 4 列状态码作为过滤条件,只输出状态码大于等于 500 的请求,并提取 IP、路径和耗时字段。这个思路同样适用于错误日志、接口耗时统计和批量命令输出分析。
`awk` 提取字段的关键,是先确认文本如何切分,再选择需要输出的列。默认空白分隔适合普通命令输出,`-F` 适合处理逗号、冒号等结构化文本;`$1`、`$2` 等字段变量负责取列,`NR` 和条件表达式负责筛行,`printf` 与 `END` 则用于格式化和统计。按这一顺序使用,`awk` 可以稳定完成文本字段提取、日志筛选和简单数据汇总。
欢迎「长按」下方图片👇,关注我们在公众号上的专业知识分享。