Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理
Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理
- Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理
- 一、正则表达式是什么?
- 二、Shell 正则表达式的两种流派
- 三、正则表达式核心元字符(必记)
- 1. 匹配单个字符
- 2. 匹配重复次数
- 3. 匹配位置(锚定符)
- 4. 分组与或逻辑
- 5. 特殊字符转义
- 四、Shell 工具实战:正则表达式的应用场景
- 场景1:用 grep 筛选文本(查找匹配内容)
- 示例1:筛选日志中的错误行
- 示例2:匹配 IP 地址
- 场景2:用 sed 批量替换文本(修改匹配内容)
- 示例1:替换配置文件中的端口号
- 示例2:删除空行和注释行(# 开头)
- 示例3:批量替换文件名中的空格
- 场景3:用 awk 处理结构化文本(提取、统计匹配内容)
- 示例1:提取日志中的时间和错误信息
- 示例2:统计每个 IP 的访问次数(访问日志)
- 示例3:匹配包含特定关键词的列
- 五、常见坑与避坑指南
- 六、总结
Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理
在 Linux 世界中,文本处理是核心技能之一,而正则表达式(Regular Expression,简称 Regex)则是文本处理的“瑞士军刀”。无论是日志分析、数据过滤、批量替换,还是脚本自动化,掌握 Shell 环境下的正则表达式,都能让你效率翻倍。本文将从基础概念出发,结合 Shell 常用工具(grep、sed、awk),带你一步步吃透正则表达式的用法,告别重复的手动操作。
一、正则表达式是什么?
正则表达式是一种模式匹配语言,通过一系列特殊字符(元字符)组合成“规则”,用来快速匹配、查找、替换文本中符合规则的字符串。它不是 Shell 专属,而是被绝大多数编程语言(Python、Java)和文本工具(Vim、VS Code)支持,但在 Shell 环境中,正则表达式的应用更偏向“命令行实战”,尤其适合处理日志、配置文件等纯文本场景。
举个简单例子:想从 1000 行日志中筛选出所有包含“ERROR”或“Warning”的行,用正则表达式 ERROR|Warning
配合 grep 命令,一行代码就能搞定,无需逐行查找。
二、Shell 正则表达式的两种流派
在 Shell 工具中,正则表达式主要分为两种语法风格,使用时需注意区分,避免踩坑:
流派 | 特点 | 支持工具 |
---|---|---|
基础正则表达式(BRE) | 元字符(如 + 、? )需加反斜杠 \ 转义才能生效 | grep(默认)、sed(默认) |
扩展正则表达式(ERE) | 元字符无需转义,语法更简洁 | grep -E、egrep、sed -E、awk |
核心区别示例:匹配“至少一个数字”
- BRE:
[0-9]\{1,\}
({}
需转义) - ERE:
[0-9]{1,}
({}
直接使用)
后续实战部分会重点演示两种流派的用法差异。
三、正则表达式核心元字符(必记)
元字符是正则表达式的“规则基石”,掌握以下核心元字符,就能应对 80% 的场景:
1. 匹配单个字符
.
:匹配任意单个字符(除了换行符\n
)
示例:a.b
可匹配acb
、a1b
、a#b
,但不匹配ab
(少一个字符)、a22b
(多一个字符)[]
:匹配括号内的任意一个字符(字符集)
示例:[abc]
匹配a
/b
/c
;[0-9]
匹配任意数字;[a-zA-Z]
匹配任意大小写字母[^]
:匹配不在括号内的任意一个字符(反向字符集)
示例:[^0-9]
匹配非数字字符;[^a-zA-Z]
匹配符号、空格等
2. 匹配重复次数
*
:匹配前面的字符0次或多次(BRE/ERE 通用,无需转义)
示例:ab*c
可匹配ac
(b 出现 0 次)、abc
(b 出现 1 次)、abbbbc
(b 出现 n 次)+
:匹配前面的字符1次或多次(BRE 需转义\+
,ERE 直接用+
)
示例:BRE 中ab\+c
、ERE 中ab+c
,均匹配abc
、abbbc
,但不匹配ac
?
:匹配前面的字符0次或1次(BRE 需转义\?
,ERE 直接用?
)
示例:ERE 中a?b
匹配b
(a 出现 0 次)、ab
(a 出现 1 次),不匹配aab
{n}
:匹配前面的字符恰好n次(BRE 需转义\{n\}
,ERE 直接用{n}
)
示例:[0-9]{3}
匹配 3 位数字(如123
、999
){n,}
:匹配前面的字符至少n次{n,m}
:匹配前面的字符n到m次(含n和m)
3. 匹配位置(锚定符)
^
:匹配行首(注意与[^]
区分,单独使用时是锚定符)
示例:^ERROR
仅匹配以ERROR
开头的行(如日志中的错误行首)$
:匹配行尾
示例:bash$
仅匹配以bash
结尾的行(如脚本文件名行)^$
:匹配空行(行首到行尾没有任何字符)\b
:匹配单词边界(单词与非单词字符的分隔处,如空格、符号、行首/行尾)
示例:\bhello\b
匹配独立的hello
单词,不匹配helloworld
或hello123
4. 分组与或逻辑
()
:分组(BRE 需转义\(
\)
,ERE 直接用()
),将多个字符视为一个整体
示例:ERE 中(ab)+
匹配ab
、abab
、ababab
(整体重复)|
:或逻辑(BRE 需转义\|
,ERE 直接用|
),匹配多个模式中的一个
示例:ERE 中ERROR|Warning|Info
匹配包含任意一个关键词的行
5. 特殊字符转义
- 若要匹配元字符本身(如
.
、*
、(
),需加反斜杠\
转义
示例:匹配 IP 地址中的.
,需写为\.
(如[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
)
四、Shell 工具实战:正则表达式的应用场景
掌握元字符后,结合 Shell 常用工具(grep、sed、awk),才能真正发挥正则的威力。以下是高频实战场景,附详细命令示例。
场景1:用 grep 筛选文本(查找匹配内容)
grep 是 Shell 中最常用的“搜索工具”,核心功能是根据正则表达式筛选行。
- 基础用法:
grep [选项] "正则表达式" 文件名
- 核心选项:
-i
:忽略大小写(如匹配error
、ERROR
、Error
)-v
:反向匹配(筛选不满足正则的行)-n
:显示匹配行的行号-E
:使用扩展正则表达式(无需转义+
、?
、()
等)-o
:仅显示匹配的字符串(而非整行)
示例1:筛选日志中的错误行
假设 app.log
中有以下内容:
2024-05-01 10:00:00 INFO 启动成功
2024-05-01 10:05:30 ERROR 数据库连接失败
2024-05-01 10:06:15 Warning 内存使用率过高
2024-05-01 10:08:00 ERROR 接口调用超时
- 筛选所有 ERROR 行(忽略大小写):
grep -i "error" app.log
- 筛选 ERROR 或 Warning 行(用 ERE 或逻辑):
grep -E "ERROR|Warning" app.log
(等价于egrep "ERROR|Warning" app.log
) - 筛选非 INFO 行(反向匹配):
grep -v "INFO" app.log
- 显示 ERROR 行的行号:
grep -n "ERROR" app.log
示例2:匹配 IP 地址
正则表达式(ERE):[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
查找文件中所有 IP 地址:
grep -E -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log
场景2:用 sed 批量替换文本(修改匹配内容)
sed 是“流编辑器”,擅长批量替换、删除文本,正则表达式是其核心匹配方式。
- 基础用法:
sed [选项] "s/正则表达式/替换内容/修饰符" 文件名
- 核心选项:
-i
:直接修改文件(不加-i
仅预览效果)-E
:使用扩展正则表达式
- 修饰符:
g
:全局替换(默认仅替换每行第一个匹配项)i
:忽略大小写p
:打印匹配行(需配合-n
选项)
示例1:替换配置文件中的端口号
假设 config.conf
中有 port = 8080
,需改为 port = 9090
:
sed -i "s/port = [0-9]{4}/port = 9090/" config.conf
(注:若用 BRE,需转义 {4}
为 \{4\}
:sed -i "s/port = [0-9]\{4\}/port = 9090/" config.conf
)
示例2:删除空行和注释行(# 开头)
清理配置文件中的无用内容:
sed -i -E "/^$|^#/d" config.conf
- 解释:
/^$|^#/
匹配空行(^$
)或 # 开头的行(^#
),d
表示删除匹配行。
示例3:批量替换文件名中的空格
假设当前目录有文件 file 1.txt
、file 2.txt
,需将空格改为下划线:
ls | sed -E "s/ /_/g" | xargs -I {} mv "{}" {}
- 解释:
sed -E "s/ /_/g"
将文件名中的空格替换为下划线,xargs
执行 mv 命令完成重命名。
场景3:用 awk 处理结构化文本(提取、统计匹配内容)
awk 擅长处理“列分隔”的结构化文本(如 CSV、日志),正则表达式可用于列匹配、条件筛选。
- 基础用法:
awk -F "分隔符" '/正则表达式/ {动作}' 文件名
示例1:提取日志中的时间和错误信息
假设日志格式为 时间 级别 内容
,需提取所有 ERROR 行的时间和内容:
awk '/ERROR/ {print $1, $2, $4}' app.log
- 解释:
/ERROR/
是正则匹配(筛选含 ERROR 的行),$1
(日期)、$2
(时间)、$4
(内容)是列索引(默认空格分隔)。
示例2:统计每个 IP 的访问次数(访问日志)
假设 access.log
中每行开头是 IP 地址(如 192.168.1.1 - - [时间] ...
):
awk '{print $1}' access.log | sort | uniq -c | sort -nr
- 解释:
{print $1}
提取第一列(IP),sort | uniq -c
统计重复次数,sort -nr
按次数倒序排列。
示例3:匹配包含特定关键词的列
筛选 /etc/passwd
中 Shell 为 /bin/bash
的用户(/etc/passwd
用 :
分隔,第7列是 Shell):
awk -F ":" '$7 ~ /\/bin\/bash/ {print $1}' /etc/passwd
- 解释:
-F ":"
指定分隔符为:
,$7 ~ /\/bin\/bash/
表示第7列匹配/bin/bash
(/
需转义为\/
),$1
是用户名。
五、常见坑与避坑指南
- 元字符转义问题:BRE 中
+
、?
、()
、{}
需转义,ERE 无需转义,用错会导致匹配失败。
解决:不确定时,优先用grep -E
、sed -E
,减少转义麻烦。 - 锚定符位置错误:
^
和$
是行首/行尾,而非字符串首尾。例如^abc$
仅匹配“整行只有 abc”,而非“包含 abc”。 - 字符集范围错误:
[a-z0-9]
是正确的(字母+数字),但[a-z-0-9]
会把-
当作范围符(若-
需作为普通字符,需放在括号开头或结尾,如[-a-z0-9]
)。 - 贪婪匹配问题:
*
和+
是“贪婪匹配”(尽可能多匹配),例如a.*b
匹配a123b456b
时,会匹配从第一个a
到最后一个b
的整个字符串。
解决:如需“非贪婪匹配”,部分工具支持(如 grep -P 支持.*?
),但 Shell 原生工具(grep/sed/awk)不支持,需通过精确字符集限制(如a[^b]*b
)。
六、总结
正则表达式是 Linux Shell 文本处理的核心,掌握它能让你从“手动筛选”升级为“自动化处理”。本文核心要点:
- 区分 BRE 和 ERE 流派,避免转义踩坑;
- 牢记核心元字符(
.
、*
、+
、^
、$
等)的用法; - 结合 grep(筛选)、sed(替换)、awk(结构化处理)三大工具,覆盖绝大多数场景;
- 多练实战(日志分析、配置修改、数据统计),才能熟练运用。
若有转载,请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/153529512