5.4.5 典型文本处理实战案例

典型文本处理实战案例#

0. 环境与工具准备(通用)#

  • 适用系统:CentOS 7+/Rocky/Ubuntu 20+
  • 安装(最小依赖):grep/sed/awk/coreutils/ss
# CentOS/Rocky
yum install -y grep sed gawk coreutils iproute
# Ubuntu
apt-get update && apt-get install -y grep sed gawk coreutils iproute2
  • 排错要点:
  • awk: command not found → 安装 gawk
  • ss: command not found → 安装 iproute2/iproute
  • 通用管道原理草图:
文章图片

1. 日志中统计请求量与状态码分布#

  • 目标:统计 Nginx 访问日志中每分钟请求数与 2xx/4xx/5xx 分布。
  • 示例数据:/var/log/nginx/access.log
# 示例:Nginx 访问日志字段说明(默认 combined)
# $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent ...

命令与解释

# 1) 抽取分钟与状态码
awk '{t=substr($4,2,17); gsub(":", " ", t); print t,$9}' /var/log/nginx/access.log > /tmp/min_status.txt
# t=YYYY/Mon/DD HH:MM  $9=状态码

# 2) 统计总量与 2xx/4xx/5xx
awk '{
  key=$1" "$2;
  cnt[key]++;
  code=substr($3,1,1);
  if(code=="2") s2[key]++; else if(code=="4") s4[key]++; else if(code=="5") s5[key]++;
}
END{
  print "time total 2xx 4xx 5xx";
  for(k in cnt) printf "%s %d %d %d %d\n", k,cnt[k],s2[k]+0,s4[k]+0,s5[k]+0
}' /tmp/min_status.txt | sort

预期输出

time total 2xx 4xx 5xx
2024/11/01 10:35 1200 1150 40 10

排错
- 状态码列不对:检查日志格式是否为 combined$9 可能需要调整。
- 时间截取异常:确认 $4[01/Nov/2024:10:35:22 形式。

练习
- 改造统计为每 5 分钟汇总(对分钟取整)。


2. 系统日志中定位登录失败与来源统计#

  • 目标:从 /var/log/secure 统计失败登录次数与来源 IP。
# 1) 取出 Failed password 行
grep "Failed password" /var/log/secure > /tmp/failed.log

# 2) 找到来源 IP(字段随发行版略有不同)
awk '{print $(NF-3)}' /tmp/failed.log | sort | uniq -c | sort -nr | head

命令解释
- $(NF-3):倒数第三列,一般为来源 IP。
- uniq -c:统计相同 IP 次数。

排错
- IP 为空:先 awk '{print NF, $0}' 查看字段数量并调整索引。
- 日志位置不同:Ubuntu 使用 /var/log/auth.log

练习
- 统计失败用户:awk '{print $(NF-5)}'(根据实际字段调整)。


3. 业务配置文件的批量键值校验#

  • 目标:校验配置文件中必填键是否缺失,并输出缺失文件列表。
  • 目录:/etc/app/*.conf
# 1) 生成示例配置(可选)
cat >/etc/app/app1.conf <<'EOF'
port=8080
host=127.0.0.1
EOF

# 2) 校验必填键
for f in /etc/app/*.conf; do
  for k in port host timeout; do
    grep -q "^$k=" "$f" || echo "$f missing $k"
  done
done

排错
- 误报:配置行有空格 key = value,可改为 grep -Eq "^\s*$k\s*=".

练习
- 输出格式改为 JSON:{"file":"xx","missing":["timeout"]}


4. 生成资源使用报表(CPU/内存/磁盘)#

  • 目标:合并 topfreedf 输出形成简报。
# 1) CPU
top -bn1 | awk -F',' '/Cpu/{print "CPU:", $1}'

# 2) 内存
free -m | awk 'NR==2{printf "MEM: used=%sMB free=%sMB\n",$3,$4}'

# 3) 磁盘
df -h | awk 'NR>1{printf "DISK: %s %s %s\n",$1,$5,$6}'

合并为脚本

cat >/usr/local/bin/sys_report.sh <<'EOF'
#!/bin/bash
echo "==== $(date '+%F %T') ===="
top -bn1 | awk -F',' '/Cpu/{print "CPU:", $1}'
free -m | awk 'NR==2{printf "MEM: used=%sMB free=%sMB\n",$3,$4}'
df -h | awk 'NR>1{printf "DISK: %s %s %s\n",$1,$5,$6}'
EOF
chmod +x /usr/local/bin/sys_report.sh
/usr/local/bin/sys_report.sh

排错
- top 输出不含 Cpu:语言环境导致,设置 LANG=C.

练习
- 将结果追加到 /var/log/sys_report.log


5. 业务慢日志中提取耗时 TopN(MySQL)#

  • 目标:从 MySQL 慢日志提取查询耗时 Top 10。
  • 假设路径:/var/log/mysql/mysql-slow.log
# 1) 提取 Query_time 与行号
grep -n "Query_time" /var/log/mysql/mysql-slow.log | awk '{print $3,$1}' | sort -nr | head

关联 SQL 语句(取耗时最高的 1 条)

# 取出第一条行号(如 1250:)
line=$(grep -n "Query_time" /var/log/mysql/mysql-slow.log | awk '{print $3,$1}' | sort -nr | head -1 | awk -F: '{print $1}')
# 从该行往后取 10 行作为 SQL 片段
sed -n "${line},$((line+10))p" /var/log/mysql/mysql-slow.log

排错
- 慢日志为空:确认 slow_query_log=ON
- Query_time 格式变化:不同版本字段可能不同。

练习
- 输出 Top10 的 SQL 起始行号与耗时到 CSV。


6. Kubernetes 事件与 Pod 异常快速定位#

  • 目标:提取异常事件并统计原因。
# 1) 获取事件并过滤 Warning
kubectl get events -A | awk '$5~/Warning/ {print $7}' | sort | uniq -c | sort -nr

命令解释
- $5:事件类型(Warning/Normal),$7:Reason(原因)。

排错
- 列位置变化:先运行 kubectl get events -A -o wide 确认列。
- 没有权限:需要 RBAC 允许 list events.

练习
- 统计每个命名空间 Warning 数:awk '$5~/Warning/ {print $1}'.


7. 批量生成 Prometheus 目标列表#

  • 目标:从主机清单生成 targets 文件。
  • 输入格式:ip,env,role
cat > /tmp/hosts.csv <<'EOF'
10.0.0.1,prod,web
10.0.0.2,prod,db
EOF

awk -F',' '{
  printf "- targets: [\"%s:9100\"]\n  labels: {env: \"%s\", role: \"%s\"}\n",$1,$2,$3
}' /tmp/hosts.csv > /etc/prometheus/targets.yml

排错
- YAML 缩进错误:确保 labels 前有两个空格。
- IP 空行:先 grep -v '^$'.

练习
- 增加 region 字段并输出到 labels。


8. 网络连接异常排查(连接数 Top)#

  • 目标:统计当前连接数 Top 端口。
ss -tan | awk 'NR>1{
  split($4,a,":"); port=a[length(a)];
  if(port!="") cnt[port]++
} END{for(p in cnt) print p,cnt[p]}' | sort -nrk2 | head

命令解释
- $4:本地地址,split 后最后一段为端口。

排错
- IPv6 格式:[::]:80 需处理 ],可先 gsub(/[]]/,"",$4)
- 空端口:跳过空值。

练习
- 按 IP+端口统计:split($5,...)


9. 目录中文件变更审计与清单比对#

  • 目标:对比两次文件清单差异。
# 1) 生成第一次快照
find /data/app -type f -printf "%P %s %TY%Tm%Td%TH%TM\n" | sort > /tmp/snapshot1.txt

# 2) 生成第二次快照
find /data/app -type f -printf "%P %s %TY%Tm%Td%TH%TM\n" | sort > /tmp/snapshot2.txt

# 3) 对比
diff -u /tmp/snapshot1.txt /tmp/snapshot2.txt | grep -E '^\+|^\-'

排错
- 时间格式不一致:确保 find 版本支持 -printf
- 目录太大:可分目录处理。

练习
- 只比较大小变化:awk '{print $1,$2}'.


10. 批量日志抽样与字段脱敏#

  • 目标:抽样日志并脱敏手机号。
# 1) 每 1000 行抽样
awk 'NR%1000==0' /var/log/app.log > /tmp/sample.log

# 2) 脱敏手机号
sed -E 's/([0-9]{3})[0-9]{4}([0-9]{4})/\1****\2/g' /tmp/sample.log > /tmp/sample_masked.log

排错
- 正则不生效:确保使用 sed -Esed -r
- 手机号格式不同:调整正则匹配规则。

练习
- 同时脱敏邮箱:s/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)/****@\2/.


本节小结#

  • 通过 grep/sed/awk/sort/uniq 管道组合实现日志分析、配置校验、资源报表与监控配置生成。
  • 每个案例均给出可执行命令、字段解释、排错提示与练习,可直接封装为脚本用于自动化运维。