awk 入门:用一行命令从日志里抽出你真正需要的字段
在云服务器上排查问题时,日志往往很长,但真正要找的只是某个字段或一组计数。awk 按行读取输入,把一行拆成字段,再执行筛选和计算。下面使用人为构造的小样本说明语法;示例输出只由这些输入推导,不代表任何线上实测结果。
一、先用小样本确认字段
把下面三行保存为 requests.log。这是自定义的空白分隔格式,依次为客户端地址、请求方法、路径、状态码和耗时毫秒,不是完整的标准访问日志。
192.0.2.10 GET /health 200 8
192.0.2.11 GET /orders 503 120
192.0.2.10 POST /orders 500 90
默认分隔方式会把连续空格或制表符作为字段边界。$1 是第一列,$NF 是最后一列,$0 则是完整原行。先输出字段数量和关键列,能避免把路径误当状态码。
awk '{print NF, $1, $4}' requests.log
对应的示例输出如下,每行都有五个字段。
5 192.0.2.10 200
5 192.0.2.11 503
5 192.0.2.10 500
二、筛选错误,再计算汇总
模式写在动作之前,只有条件为真才执行花括号中的语句。这里同时检查字段数和状态码形态,避免格式不全的行混入结果。
awk 'NF == 5 && $4 ~ /^5[0-9][0-9]$/ {print $1, $3, $4}' requests.log
示例输出只包含两条错误请求,不包含成功的健康检查。
192.0.2.11 /orders 503
192.0.2.10 /orders 500
如果只需要错误请求的数量与平均耗时,可以累加第五列,在读取结束后统一计算。先判断计数,能避免没有匹配行时除以零。
awk 'NF == 5 && $4 ~ /^5[0-9][0-9]$/ {n++; total += $5}
END {if (n) print n, total/n; else print "no matching requests"}' requests.log
本样本的示例输出为下面两个数字,分别表示请求数和平均耗时,单位沿用输入中的毫秒。
2 105
三、处理引号和分隔符的边界
命令外层使用单引号,是为了让 shell 不提前展开 $1 等字段变量;awk 内部的字符串则用双引号。需要传入路径变量时,优先使用参数绑定,不要把外部内容拼进程序文本。
awk -v target='/orders' '$3 == target {print $0}' requests.log
awk -F: '{print $1, $NF}' /etc/passwd
第二条命令改用冒号分隔,适合该文件的字段结构。但指定逗号分隔并不等于理解 CSV:带引号的逗号、跨行字段都需要专门的解析器。真实访问日志中的时间、请求行和代理信息也可能改变列号,不能机械套用样本。
最后,先在副本上核对几行输入和预期输出,再扩大到整份日志。空文件、缺失字段、耗时含单位或非数字,都值得单独检查;awk 的自动类型转换不会替你验证数据。把格式假设写在脚本注释中,比追求最短的一行命令更利于复用。
四、让计数结果可解释
如果要按客户端统计次数,可以用关联数组保存每个地址的计数,再在结束阶段逐项输出。数组遍历的顺序不应被当作排名,需要明确排序规则。还应先决定统计口径:一行是否必然代表一次请求,重试是否算独立请求,空白行和注释行如何处理。这些问题不由工具自动决定。
检查结果时,可以把成功与失败请求分别计数,确认它们之和是否等于有效输入行数。若对不上,先寻找格式异常行,而不是直接把差额解释为丢失请求。小样本算得对,只说明表达式符合样本,不能保证它适配所有日志变体。
- 点赞
- 收藏
- 关注作者
评论(0)