Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理

Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理

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 可匹配 acba1ba#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,均匹配 abcabbbc,但不匹配 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 位数字(如 123999
  • {n,}:匹配前面的字符至少n次
  • {n,m}:匹配前面的字符n到m次(含n和m)

3. 匹配位置(锚定符)

  • ^:匹配行首 (注意与 [^] 区分,单独使用时是锚定符)
    示例:^ERROR 仅匹配以 ERROR 开头的行(如日志中的错误行首)
  • $:匹配行尾
    示例:bash$ 仅匹配以 bash 结尾的行(如脚本文件名行)
  • ^$:匹配空行(行首到行尾没有任何字符)
  • \b:匹配单词边界 (单词与非单词字符的分隔处,如空格、符号、行首/行尾)
    示例:\bhello\b 匹配独立的 hello 单词,不匹配 helloworldhello123

4. 分组与或逻辑

  • ():分组(BRE 需转义 \( \),ERE 直接用 ()),将多个字符视为一个整体
    示例:ERE 中 (ab)+ 匹配 abababababab(整体重复)
  • |:或逻辑(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:忽略大小写(如匹配 errorERRORError
    • -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.txtfile 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 是用户名。

五、常见坑与避坑指南

  1. 元字符转义问题 :BRE 中 +?(){} 需转义,ERE 无需转义,用错会导致匹配失败。
    解决:不确定时,优先用 grep -Esed -E,减少转义麻烦。
  2. 锚定符位置错误^$ 是行首/行尾,而非字符串首尾。例如 ^abc$ 仅匹配"整行只有 abc",而非"包含 abc"。
  3. 字符集范围错误[a-z0-9] 是正确的(字母+数字),但 [a-z-0-9] 会把 - 当作范围符(若 - 需作为普通字符,需放在括号开头或结尾,如 [-a-z0-9])。
  4. 贪婪匹配问题*+ 是"贪婪匹配"(尽可能多匹配),例如 a.*b 匹配 a123b456b 时,会匹配从第一个 a 到最后一个 b 的整个字符串。
    解决:如需"非贪婪匹配",部分工具支持(如 grep -P 支持 .*?),但 Shell 原生工具(grep/sed/awk)不支持,需通过精确字符集限制(如 a[^b]*b)。

六、总结

正则表达式是 Linux Shell 文本处理的核心,掌握它能让你从"手动筛选"升级为"自动化处理"。本文核心要点:

  1. 区分 BRE 和 ERE 流派,避免转义踩坑;
  2. 牢记核心元字符(.*+^$ 等)的用法;
  3. 结合 grep(筛选)、sed(替换)、awk(结构化处理)三大工具,覆盖绝大多数场景;
  4. 多练实战(日志分析、配置修改、数据统计),才能熟练运用。

若有转载,请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/153529512

相关推荐
lhxcc_fly3 小时前
Linux网络--6、网络层
linux·网络·ip
刺客xs3 小时前
linux GDB调试器
linux·运维·windows
Wang's Blog4 小时前
MySQL: 高并发电商场景下的数据库架构演进与性能优化实践
mysql·性能优化·数据库架构
程序新视界5 小时前
什么是MySQL JOIN查询的驱动表和被驱动表?
数据库·后端·mysql
wydaicls5 小时前
Linux 内核伙伴系统在快速路径分配内存时,对一个内存区域(Zone)进行水位线检查和内存压力评估的关键逻辑
linux·服务器
今天只学一颗糖5 小时前
Linux学习笔记--GPIO子系统和PinCtrl子系统
linux·笔记·学习
黄昏晓x5 小时前
Linux----权限
linux·运维·服务器
小白不想白a5 小时前
【shell】每日shell练习(系统服务状态监控/系统性能瓶颈分析)
linux·运维·服务器
一匹电信狗6 小时前
【MySQL】数据库的相关操作
linux·运维·服务器·数据库·mysql·ubuntu·小程序