本文要点
- 正则表达式(Regular Expression)是一套用元字符描述文本模式的语法,贯穿
grep、sed、awk三大文本处理工具。 - 字符类
[abc]、量词* + ? {n}、锚点^ $、分组()与转义\.是必须掌握的核心元字符。 grep默认用基本正则(BRE),加-E切换到扩展正则(ERE),+ ? | ()不再需要转义。grep -o只打印实际匹配的片段,grep -c统计匹配行数,用于从日志中精确抽取 IP、端口等字段。awk既可按正则筛选整行(/pattern/{...}),也能按正则匹配单个字段($n ~ /re/)。
什么是正则表达式
正则表达式(Regular Expression,简称 regex)是一套用来描述文本模式的迷你语言。它把"含有数字的 IP"、"以 ERROR 开头的行"这类模糊需求,翻译成机器可执行的模式串。Linux 命令行中三个最常用的文本工具——grep、sed、awk——都以正则表达式为匹配核心,因此掌握正则就是掌握三剑客的共同基础。
本文以一份模拟的服务器日志为例,在 Ubuntu 24.04 上真实执行每条命令,带你系统过一遍元字符、定位与分组,以及它们在 grep、sed、awk 中的实际应用。
准备演示数据
先在服务器上创建一份 7 行的日志文件 /root/net.log,模拟包含不同级别(INFO/WARN/ERROR)、IP、端口与服务的应用日志:
cat > /root/net.log <<'LOG'
2026-08-20 10:11:22 ERROR Failed to connect to db.srv:5432
2026-08-20 10:12:03 INFO User astarry logged in from 192.168.1.10
2026-08-20 10:12:45 WARN Slow query 1.2s on orders table
2026-08-20 10:15:18 ERROR Timeout connecting to cache.srv:6379
2026-08-20 10:16:02 INFO User root ran sudo apt update
2026-08-20 10:20:33 ERROR Connection refused on 10.0.0.5:8080
2026-08-20 10:22:11 INFO Backup completed in 45s
LOG观察文件结构:每行由时间戳(日期 + 时分秒)、级别、消息三部分组成,其中 INFO 是普通信息、WARN 是警告、ERROR 是错误。后面所有演示都基于这份数据。
核心元字符
正则表达式的核心是十几个元字符,它们各自代表一类匹配规则。先记住最常用的几组。
字符类 [...]
方括号表示"匹配括号内任意一个字符"。例如:
[0-9]匹配任意一个数字,等价于[0123456789][a-z]匹配任意一个小写字母[A-Za-z]匹配任意一个字母(大小写均可)[^0-9]中的^在方括号内表示"取反",匹配任意一个非数字字符
量词 * + ? {n}
量词修饰它前面的字符或分组,表示"出现多少次":
| 量词 | 含义 | 示例 |
|---|---|---|
* | 前一项出现 0 次或多次 | a* 匹配空、a、aaa |
+ | 前一项出现 1 次或多次 | a+ 匹配 a、aaa,不匹配空 |
? | 前一项出现 0 次或 1 次 | colou?r 同时匹配 color 和 colour |
{n} | 前一项恰好 n 次 | [0-9]{4} 匹配 4 位数字 |
{n,} | 前一项至少 n 次 | [0-9]{2,} 匹配 2 位及以上数字 |
{n,m} | 前一项 n 到 m 次 | [0-9]{2,4} 匹配 2 到 4 位数字 |
锚点 ^ 与 $
^ 匹配行首,$ 匹配行尾(在非多行模式下分别匹配字符串开头与结尾):
^ERROR匹配ERROR开头的行ERROR$匹配ERROR结尾的行^$匹配空行
分组 () 与分支 |
(pattern)把一部分模式括成分组,可整体被量词修饰、被捕获引用、或用于替换A|B表示或,匹配A或B
转义 \
. 在正则里是一个元字符,代表"任意一个字符"。要匹配字面上的点号(如 IP 中的小数点 192.168.1.10),必须写成 \.。类似地,( ) { } [ ] * + ? ^ $ | 这些元字符要匹配字面值时,都需用 \ 转义。
grep:最常用的匹配工具
grep 按正则逐行扫描文件,把匹配的行打印出来。
普通匹配与行号
最简单的用法是把普通字符串当模式,匹配包含该字符串的行,-n 显示行号:
grep -n "ERROR" /root/net.log1:2026-08-20 10:11:22 ERROR Failed to connect to db.srv:5432
4:2026-08-20 10:15:18 ERROR Timeout connecting to cache.srv:6379
6:2026-08-20 10:20:33 ERROR Connection refused on 10.0.0.5:8080基本正则与扩展正则:-E 开关
grep 默认使用基本正则(BRE),此时 + ? | ( ) 这些元字符需要加 \ 才有特殊含义(如 a\+)。加上 -E 切换到扩展正则(ERE),这些字符直接生效,更直观。日常使用几乎都用 -E。请看下面对比——扩展正则下 | 直接表示"或":

grep -nE "ERROR|WARN" /root/net.log1:2026-08-20 10:11:22 ERROR Failed to connect to db.srv:5432
3:2026-08-20 10:12:45 WARN Slow query 1.2s on orders table
4:2026-08-20 10:15:18 ERROR Timeout connecting to cache.srv:6379
6:2026-08-20 10:20:33 ERROR Connection refused on 10.0.0.5:8080统计与抽取:-c 与 -o
grep -c "模式" 文件统计匹配的行数,而不是匹配次数:
grep -c "ERROR" /root/net.log3grep -o "模式" 文件只打印实际匹配到的片段(而不是整行)。这对从日志里抽取 IP、端口等字段非常有用。用一个字符类 + 量词 + 转义点的正则来抽取全部 IP 地址:

grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" /root/net.log192.168.1.10
10.0.0.5这里 [0-9]+ 匹配 1 到多位数字,\. 匹配字面点号,四组数字用三个点连接就是 IPv4 地址的模式。文件中只有第 2、6 行出现了完整 IPv4,因此抽取到两条。
同样的思路可以抽取端口号。端口是冒号后接 4 位数字,用 :[0-9]{4}:
grep -oE ":[0-9]{4}" /root/net.log:5432
:6379
:8080以及连接的服务名(db.srv、cache.srv):
grep -oE "[a-z]+\.srv" /root/net.logdb.srv
cache.srv单词边界 \b
\b 匹配单词边界,用于精确匹配而不是前缀匹配。例如要匹配独立的单词 connect,而不是 connecting:
grep -nE "\bconnect\b" /root/net.log1:2026-08-20 10:11:22 ERROR Failed to connect to db.srv:5432第 4 行虽然也有 connecting,但因为它不是独立的 connect 单词,未被匹配到。
锚点的一个易错点
^ERROR 只匹配 ERROR 位于行首的行。在本日志里,级别字段前面还有时间戳,所以 ^ERROR 不会有任何输出:
grep -n "^ERROR" /root/net.log(无输出)这说明:模式的锚点必须与文本实际位置吻合,否则匹配不上。
sed:按正则做流式替换与筛选
sed 是流编辑器,能逐行读入、按正则替换或删除/保留内容。
替换:s/模式/替换/
用 s/模式/替换/ 替换匹配部分。例如删掉每行开头的时间戳(日期 时分秒 + 空格,即 ^[0-9-]* [0-9:]* ):
sed -n "s/^[0-9-]* [0-9:]* //p" /root/net.logERROR Failed to connect to db.srv:5432
INFO User astarry logged in from 192.168.1.10
WARN Slow query 1.2s on orders table
ERROR Timeout connecting to cache.srv:6379
INFO User root ran sudo apt update
ERROR Connection refused on 10.0.0.5:8080
INFO Backup completed in 45s这里的 ^[0-9-]* 从行首匹配数字和连字符(日期),[0-9:]* 继续匹配 10:11:22(时分秒),整体被替换为空。-n 关闭默认打印,p 只在发生替换时打印该行。
sed 替换中还支持分组引用。正则里用 \( \)(基本正则)或 ( )(扩展正则配合 -E)分组,替换串里用 \1、\2 引用。例如只保留"日期 时间"两段:
sed -nE "s/^([0-9-]+) ([0-9:]+).*/\1 \2/p" /root/net.log2026-08-20 10:11:22
2026-08-20 10:12:03
2026-08-20 10:12:45
2026-08-20 10:15:18
2026-08-20 10:16:02
2026-08-20 10:20:33
2026-08-20 10:22:11([0-9-]+) 是第一组(日期)、([0-9:]+) 是第二组(时间),.* 吃掉剩余部分,替换为 \1 \2 就只剩日期和时间。
按正则删除:/模式/d
/模式/d 表示删除匹配该正则的行。例如删除所有 ERROR 行,只留下 INFO/WARN:
sed -n "/ERROR/d; p" /root/net.log2026-08-20 10:12:03 INFO User astarry logged in from 192.168.1.10
2026-08-20 10:12:45 WARN Slow query 1.2s on orders table
2026-08-20 10:16:02 INFO User root ran sudo apt update
2026-08-20 10:22:11 INFO Backup completed in 45sawk:正则筛选 + 字段处理
awk 按列处理文本,默认用空白分隔字段,$1、$2……分别代表第 1、2……列,$0 代表整行,$NF 代表最后一列。awk 把正则用得最灵活——既能筛选整行,也能匹配单个字段。
按整行正则筛选
/正则/ {动作} 表示"匹配该正则的行执行动作"。日志里第 3 列是级别,筛出 ERROR 或 WARN 的行,并打印第 2 列(时间)和第 3 列(级别):

awk '/ERROR|WARN/ {print $2, $3}' /root/net.log10:11:22 ERROR
10:12:45 WARN
10:15:18 ERROR
10:20:33 ERROR正则表达式用在两个斜杠 / 之间,写法与 grep 一致。
按字段正则匹配:$n ~ /re/
awk 的一个强大之处是可以只对某一列做正则匹配。$n ~ /正则/ 表示"第 n 列匹配该正则"。例如找出 User 后面是 root 的行($4 是 User、$5 是用户名),打印日期、时间、用户:
awk '$4 ~ /User/ && $5=="root" {print $1, $2, $4, $5}' /root/net.log2026-08-20 10:16:02 User root~ 是"匹配"运算符,!~ 表示"不匹配"。字段值判断(==)配合正则(~),让 awk 能精确处理结构化文本。
正则统计思路
用 awk 结合正则与排序,可以快速统计各级别日志的条数:
awk '{print $3}' /root/net.log | sort | uniq -c 3 ERROR
3 INFO
1 WARN先 awk 抽出第 3 列级别,sort 排序,再用 uniq -c 计数,一条管道就得出 ERROR 3 条、INFO 3 条、WARN 1 条——这与日志里三类级别的实际行数完全吻合。这正是日志分析的常见套路。
BRE 与 ERE:理解 cron、sed 等处的差异
最后澄清一个关键概念:正则有两种方言。
- 基本正则(BRE):
grep(不带-E)、sed(不带-E)、grep脚本、老的vi默认使用。在 BRE 中,+、?、|、(、)、{、}只是普通字符,要当元字符必须写成\+、\?、\|、\(、\)、\{、\}。 - 扩展正则(ERE):
grep -E、egrep、sed -E、awk使用。+、?、|、(、)、{、}直接是元字符,不需要转义。
awk 一出生就用 ERE,所以前面的 awk 例子直接写了 ERROR|WARN 和 [0-9]+ 而没有转义。而 sed、grep 默认是 BRE,需要 -E 才能用同样的写法(分组的转义写法也因此在两者间不同)。搞清这个差异,很多"同样的正则为什么在不同工具里表现不同"的困惑就解开了。
常用正则速查表
| 元字符 | 含义 | 示例 | ||
|---|---|---|---|---|
. | 任意一个字符 | a.c 匹配 abc、a1c | ||
[...] | 括号内任意一个字符 | [0-9] 数字、[a-z] 小写 | ||
[^...] | 除括号内外的任意字符 | [^0-9] 非数字 | ||
* | 前项 0 次或多次 | ab*c 匹配 ac、abbc | ||
+ | 前项 1 次或多次(ERE) | ab+c 匹配 abc、abbc | ||
? | 前项 0 次或 1 次(ERE) | colou?r 匹配 color/colour | ||
{n,m} | 前项 n~m 次 | [0-9]{2,4} | ||
^ | 行首(方括号内取反) | ^INFO | ||
$ | 行尾 | INFO$ | ||
\b | 单词边界 | \bconnect\b | ||
() | 分组(可供替换引用) | (ab)+ | ||
| ` | ` | 或(ERE) | `ERROR | WARN`(ERE) |
\. \( 等 | 转义元字符的字面值 | \.srv 匹配 .srv |
小结
正则表达式是 Linux 文本处理的地基。记住四组核心元字符——字符类、量词、锚点、分组与分支,再用 grep -o/-c、sed s///、awk 字段匹配这几个高频组合去练习,就能覆盖绝大多数日志分析与配置处理场景。三剑客虽然命令不同,但正则是它们共用的"语言",会了正则,grep/sed/awk 的多数功能都可触类旁通。
如果你想进一步深入,推荐阅读 Regular-Expressions.info 的教程(英文权威参考)或系统自带的 man grep、man sed、man awk 手册页(直接 man grep 在终端查看全部基础正则与扩展正则语法说明)。
评论 (0)
暂无评论,快来抢沙发吧!