Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理
- [Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理](#Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理)
-
- 一、正则表达式是什么?
- [二、Shell 正则表达式的两种流派](#二、Shell 正则表达式的两种流派)
- 三、正则表达式核心元字符(必记)
-
- [1. 匹配单个字符](#1. 匹配单个字符)
- [2. 匹配重复次数](#2. 匹配重复次数)
- [3. 匹配位置(锚定符)](#3. 匹配位置(锚定符))
- [4. 分组与或逻辑](#4. 分组与或逻辑)
- [5. 特殊字符转义](#5. 特殊字符转义)
- [四、Shell 工具实战:正则表达式的应用场景](#四、Shell 工具实战:正则表达式的应用场景)
-
- [场景1:用 grep 筛选文本(查找匹配内容)](#场景1:用 grep 筛选文本(查找匹配内容))
-
- 示例1:筛选日志中的错误行
- [示例2:匹配 IP 地址](#示例2:匹配 IP 地址)
- [场景2:用 sed 批量替换文本(修改匹配内容)](#场景2:用 sed 批量替换文本(修改匹配内容))
-
- 示例1:替换配置文件中的端口号
- [示例2:删除空行和注释行(# 开头)](# 开头))
- 示例3:批量替换文件名中的空格
- [场景3:用 awk 处理结构化文本(提取、统计匹配内容)](#场景3:用 awk 处理结构化文本(提取、统计匹配内容))
-
- 示例1:提取日志中的时间和错误信息
- [示例2:统计每个 IP 的访问次数(访问日志)](#示例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