服务公告
正则表达式:正则最佳实践
发布时间:2026-04-23 13:01
前言
搞过日志分析的人都知道,最烦的是写出一堆正则结果跑出来对不上号。本教程讲讲生产环境中真正能跑的正则最佳实践,从基础到高阶,从理论到踩坑。别整那些学院派花活,咱聊点实际能用的。
一、基础概念先捋清楚
正则这东西,入门简单想精通难。先把几个核心概念搞明白,后面的命令才能看懂。
1. 字符类与元字符
字符类是最基础的,[] 里面放要匹配的字符范围。
示例:匹配数字
[0-9]
等价于 \d,但生产环境里\d更简洁
示例:匹配字母
[a-zA-Z]
注意大小写敏感,这坑踩过的人不少
预期输出示例:
# 测试字符串 "abc123DEF456"
# 正则 [0-9]+ 匹配到 "123" 和 "456"
# 正则 [a-z]+ 匹配到 "abc"
# 正则 [A-Z]+ 匹配到 "DEF"
2. 量词与贪婪/非贪婪
量词决定匹配多少,贪婪和非贪婪的区别能让你debug到怀疑人生。
贪婪模式(匹配最多)
# grep -E '".*"' 文件 # 会匹配从第一个"到最后一个"的所有内容
非贪婪模式(匹配最少)
# grep -E '".*?"' 文件 # 每个"..."单独匹配
预期输出示例:
字符串: "hello" world "test"
贪婪匹配".*": "hello" world "test" # 整个串
非贪婪匹配".*?": "hello" 和 "test" # 分开匹配
二、生产环境常用命令
步骤1:grep精确匹配日志
# CentOS/RHEL/Ubuntu通用
grep -E 'error|warn|critical' /var/log/messages
预期输出:
Jan 15 10:23:45 server01 kernel: error: connection timeout
Jan 15 10:24:12 server01 nginx[1234]: warn: upstream failed
Jan 15 10:25:01 server01 CRON[5678]: critical: backup failed
步骤2:sed批量替换(带备份)
# CentOS/RHEL
sed -i.bak 's/old_pattern/new_pattern/g' /etc/app/config.conf
# Ubuntu
sudo sed -i 's/old_pattern/new_pattern/g' /etc/app/config.conf
警告:-i参数会直接修改文件,先备份!先备份!先备份!
预期输出:
# 执行后生成 config.conf.bak 备份文件
# 原文件已替换
步骤3:awk提取特定字段
# CentOS/RHEL/Ubuntu
awk -F: '/nginx/ {print $1, $3}' /var/log/nginx/access.log
预期输出:
10.0.0.1 200
10.0.0.2 404
10.0.0.3 200
10.0.0.1 500
步骤4:find配合正则查找文件
# CentOS/RHEL/Ubuntu
find /var/log -regex '.*/[0-9]{8}\.log$'
预期输出:
/var/log/nginx/access.20240115.log
/var/log/nginx/access.20240116.log
/var/log/nginx/error.20240115.log
步骤5:nginx日志统计实战
# 统计404请求的来源IP
cat /var/log/nginx/access.log | grep " 404 " | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
预期输出:
156 192.168.1.100
89 10.0.0.55
34 172.16.0.23
12 203.0.113.50
步骤6:nginx日志提取URL参数
# 提取请求路径和状态码(Ubuntu/CentOS通用)
awk 'match($7, /\/api\/[^\?]+/) {print substr($7, RSTART, RLENGTH), $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
预期输出:
2345 /api/users
1890 /api/orders
567 /api/products
123 /api/settings
三、常见问题FAQ
Q1:正则跑出来结果不对,怎么排查?
先把正则拆开逐步测试,别一口气写完。例如你想匹配IP,先单独测试匹配数字段,再组装。
# 单独测试各部分
echo "192.168.1.100" | grep -E '[0-9]+' # 验证数字匹配
echo "192.168.1.100" | grep -E '\.' # 验证点号转义
echo "192.168.1.100" | grep -E '^[0-9.]+$' # 完整IP正则
Q2:grep -E 和 grep -P 有什么区别?
-E 用的是扩展正则(ERE),-P 用的是Perl正则(PCRE)。生产环境优先用-E,兼容性更好。-P 功能强但部分系统不支持。
# CentOS/RHEL
grep -E '\d+' /var/log/messages # 扩展正则
# Ubuntu
grep -E '\d+' /var/log/syslog # 同样有效
Q3:为什么我的正则匹配不到空行?
空行匹配要用 ^$ 而不是 ^\s*$。如果还有问题,检查文件编码和行尾符。
# CentOS/RHEL
grep -E '^$' /var/log/secure # 匹配空行
# Ubuntu
grep -E '^$' /var/log/auth.log # 匹配空行
# 检查文件编码(通用)
file /var/log/messages
Q4:sed替换想限制范围怎么写?
用行号限制替换范围,或者用地址模式。
# CentOS/RHEL/Ubuntu
# 只替换第10-20行的内容
sed -i '10,20s/old/new/g' file.conf
# 只替换包含关键词的行
sed -i '/database/s/old/new/g' file.conf
# 多个模式
sed -i '/pattern1/,/pattern2/s/old/new/g' file.conf
四、总结
核心要点
- 正则不是写得越短越好,能读懂才是关键
- 生产环境先备份再操作,别相信自己的正则不会翻车
- grep -E最通用,awk最灵活,sed适合批量替换
- 遇到复杂匹配先拆解测试,不要一口气写完
- 不同发行版路径不同,但正则语法基本通用
延伸阅读
- man grep / man sed / man awk —— 官方文档永远最准
- 《正则表达式必知必会》—— 工具书,案头备一本
- regex101.com —— 在线调试正则,帮你验证语法
- 《Linux命令行与shell脚本编程大全》—— 第15章正则部分讲得细
记住,正则这东西,得多练多踩坑。踩的坑多了,自然就熟了。