18 .shell编程-正则表达式

学会 正则表达式(Regular Expression,简称 regex) 是 Shell 编程里从"会写脚本"到"会处理数据"的关键一步。

它让你能轻松地筛选、匹配、提取文本信息,是日志分析、批量处理、数据清洗的利器。

下面我来系统讲解:

什么是正则、怎么在 Shell 里用、有哪些工具支持、常见模式与实战例子。


🧠 一、正则表达式是什么?

正则表达式是一种 文本匹配模式(pattern)

它描述了一类字符串的结构,用来进行:

  • 搜索(search)
  • 替换(replace)
  • 验证(validate)
  • 提取(extract)

在 Shell 中,常用的工具如:

  • grep
  • egrep / grep -E
  • sed
  • awk
  • expr

都支持正则表达式。


⚙️ 二、Shell 中正则的主要使用场景

命令 用途 是否支持正则
grep 搜索文本匹配行
sed 查找并替换文本
awk 模式匹配与处理
expr 简单正则提取
[[ =~ ]] Bash 内置模式匹配 ✅(Bash 3+)

📘 三、基本正则表达式符号(BRE)

符号 含义 示例 匹配
. 任意单个字符 a.b a1b, acb
* 前一个字符重复 0 次或多次 lo*l ll, lool, looooool
^ 匹配行首 ^abc "abc..." 开头的行
$ 匹配行尾 abc$ 以 "abc" 结尾的行
[] 字符集匹配 [0-9] 任意数字
[^] 取反匹配 [^0-9] 非数字字符
\{m,n\} 匹配前项 m 到 n 次 a\{2,4\} aa, aaa, aaaa

🔎 四、扩展正则(ERE)------ grep -Eegrep

扩展正则支持更多符号:

符号 含义 示例 说明
+ 前项至少出现一次 a+b 匹配 abaab 重复匹配
? 前项可有可无 colou?r 匹配 colorcolour 可选项
` ` 或关系 `cat
() 分组 (ab)+ 匹配 "ab"、"abab" 捕获分组
{m,n} 限定重复次数 a{2,4} 匹配 "aa"、"aaa"、"aaaa" 次数限定

🧩 五、grep 命令:最常用的正则工具

1️⃣ 基本用法

bash 复制代码
grep "root" /etc/passwd

匹配包含 "root" 的行。


2️⃣ 使用正则匹配复杂模式

bash 复制代码
grep -E "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" users.txt

匹配邮箱地址。


3️⃣ 区分大小写 / 忽略大小写

bash 复制代码
grep -i "hello" file.txt

4️⃣ 统计匹配行数

bash 复制代码
grep -c "error" /var/log/syslog

5️⃣ 只显示匹配部分

bash 复制代码
grep -oE "[0-9]+" file.txt

提取所有数字。


🧰 六、sed 命令:替换与编辑

sed(stream editor)也是正则的好搭档。

示例 1:替换单词

bash 复制代码
sed 's/apple/banana/g' fruits.txt

把所有 apple 替换成 banana


示例 2:只替换行首出现的单词

bash 复制代码
sed 's/^apple/banana/'

示例 3:删除空行

bash 复制代码
sed '/^$/d'

🧮 七、awk 与正则结合

awk 的语法是 pattern { action }

示例:

bash 复制代码
awk '/error/ { print $1, $2 }' /var/log/syslog

匹配包含 "error" 的行,输出前两列。


示例:匹配以数字开头的行

bash 复制代码
awk '/^[0-9]/ { print $0 }' data.txt

⚡ 八、在 Bash 中直接用正则([[ =~ ]]

Bash 3.0 之后支持直接在 if 中匹配正则:

bash 复制代码
#!/bin/bash
read -p "输入邮箱:" email

if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
    echo "邮箱格式正确"
else
    echo "邮箱格式错误"
fi

✅ 优点:无需 grepsed 等外部命令

🚫 注意:[[ =~ ]] 右侧的正则不要加引号,否则不会生效。


🔍 九、expr 也能用简单正则

bash 复制代码
expr "hello123" : '.*\([0-9][0-9][0-9]\)'

输出:123

表示匹配并提取字符串中的最后三位数字。


📘 十、常见正则模式速查表

目标 正则表达式 示例匹配
邮箱 ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ abc@163.com
手机号(中国) ^1[3-9][0-9]{9}$ 13812345678
IPv4 地址 ^([0-9]{1,3}\.){3}[0-9]{1,3}$ 192.168.0.1
日期(YYYY-MM-DD) ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ 2025-10-10
整数 ^-?[0-9]+$ -42, 123
浮点数 ^-?[0-9]+\.[0-9]+$ 3.14, -0.25

🧠 十一、实战:批量提取 IP 地址

bash 复制代码
#!/bin/bash
# 从日志文件中提取所有 IP

grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log | sort | uniq -c | sort -nr

功能:

  1. grep 匹配所有 IP;
  2. uniq -c 统计出现次数;
  3. sort -nr 按次数排序。

✅ 十二、总结

工具 支持正则 用途
grep 搜索匹配行
sed 查找/替换文本
awk 复杂文本处理
expr 简单提取
[[ =~ ]] Bash 原生匹配

sed + 正则表达式

这部分内容能让人在日志分析、配置批处理、数据清洗中如虎添翼。

接下来我将从基础到高级讲解,包括分组、反向引用、条件替换、行匹配与多行操作。


🧠 一、sed 是什么?

sedstream editor )是一个流编辑器,用于:

  • 查找(Search)
  • 替换(Substitute)
  • 删除(Delete)
  • 插入(Insert)
  • 提取(Print)

它一次读一行,对每一行执行给定的命令(如替换或删除)。

最常用命令格式:

bash 复制代码
sed 's/正则表达式/替换内容/修饰符' file

⚙️ 二、基本替换命令:s///

功能 示例 说明
简单替换 sed 's/apple/banana/' 每行替换第一个匹配项
全局替换 sed 's/apple/banana/g' 替换每行所有匹配
替换后输出 sed -n 's/apple/banana/p' 不显示原文,只显示替换结果
就地修改 sed -i 's/apple/banana/g' file.txt 直接修改文件内容(危险操作!)

🧩 三、正则表达式在 sed 中的作用

sed 默认支持 基本正则表达式(BRE)

若要使用 扩展正则表达式(ERE) (如 +, ?, |),需加 -E 选项。

bash 复制代码
sed -E 's/[0-9]+/NUM/g'

🧱 四、分组与反向引用(重点🔥)

sed 中,括号需要转义

  • \(\) 表示"分组"
  • \1, \2, ... 表示反向引用(即捕获组)

示例 1:交换字段位置

输入文件:

复制代码
first last
Tom Smith
Alice Brown

命令:

bash 复制代码
sed 's/\([A-Za-z]*\) \([A-Za-z]*\)/\2, \1/' names.txt

输出:

复制代码
Smith, Tom
Brown, Alice

🧩 解释:

  • \([A-Za-z]*\) 第一个名字
  • \([A-Za-z]*\) 第二个名字
  • \2, \1 表示"第二组,逗号,第一组"

示例 2:提取数字部分

bash 复制代码
echo "Order1234" | sed 's/[^0-9]*\([0-9]*\).*/\1/'

输出:

复制代码
1234

解释:

  • [^0-9]* → 非数字开头部分
  • \([0-9]*\) → 捕获数字部分
  • .* → 后续任意内容
  • \1 → 返回数字组内容

🧮 五、使用分隔符灵活替换

默认分隔符是 /,但路径中常含 /

可以用其他符号(如 #@)代替:

bash 复制代码
sed 's#/usr/local/bin#/opt/tools#g'

这样就不必对斜杠转义了。


🔍 六、匹配行:只替换特定模式

bash 复制代码
sed '/^user/ s/enabled/disabled/' config.txt

含义:

  • 只处理以 user 开头的行;
  • enabled 替换为 disabled

🧰 七、删除行与插入行

操作 示例 效果
删除匹配行 sed '/^#/d' 删除所有以 # 开头的注释行
删除空行 sed '/^$/d' 删除空行
在匹配后插入行 sed '/pattern/a\New line here' 在匹配行后加内容
在匹配前插入行 sed '/pattern/i\Insert before' 在匹配行前加内容

🧠 八、使用"多命令"模式:-e{}

示例:

bash 复制代码
sed -e 's/foo/bar/' -e 's/hello/hi/'

或:

bash 复制代码
sed '/^user/ {
    s/enabled/disabled/
    s/guest/standard/
}'

🧩 九、sed -E:扩展正则更强大

支持 +, ?, |, ()(不用加 \):

bash 复制代码
sed -E 's/(cat|dog)/animal/g' pets.txt

匹配 catdog 并替换为 animal


🔄 十、使用反向引用进行复杂替换

示例:日期格式转换

输入:

复制代码
2025-10-10

命令:

bash 复制代码
sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'

输出:

复制代码
10/10/2025

🧩 拆解:

  • ([0-9]{4}) → 年
  • ([0-9]{2}) → 月
  • ([0-9]{2}) → 日
    组合为 \3/\2/\1

🧠 十一、匹配多行(进阶)

标准 sed 一次处理一行,但可用 N 命令拼接多行。

例如:合并相邻两行

bash 复制代码
sed 'N; s/\n/ /'

🧮 十二、配合 Shell 正则使用

bash 复制代码
for file in *.log; do
    sed -i -E 's/error|fail/ERROR/g' "$file"
done

对所有 .log 文件,将 "error" 或 "fail" 替换为大写 "ERROR"。


🧾 十三、实战综合例子

示例:清洗 Nginx 访问日志

目标:提取 IP 和访问路径

日志行:

复制代码
192.168.1.10 - - [10/Oct/2025:10:20:30 +0800] "GET /index.html HTTP/1.1" 200 512

命令:

bash 复制代码
sed -E 's/^([0-9.]+).*"GET ([^ ]*).*/\1\t\2/' access.log

输出:

复制代码
192.168.1.10	/index.html

🧰 十四、修饰符总结

修饰符 作用
g 全局替换(每行所有匹配)
p 打印匹配结果
i 不区分大小写
w file 将匹配结果写入文件
I 大小写不敏感(GNU sed)

✅ 十五、总结与建议

技能 关键知识点
替换 s/regex/replace/g
捕获组 \( \)\1
行过滤 /pattern/
分隔符 s#old#new#
扩展正则 sed -E
就地修改 -i
多命令 { ... }

shell编程中基本正则与扩展正则需不需加反斜杠的问题

为什么有的正则要加反斜杠、有的不需要。


🧩 一、Shell 正则的两大"体系"

在 Shell(尤其是 grep, sed, awk 等工具)中,

实际上存在 两种正则表达式语法体系

名称 英文全称 常见命令参数 特点
基本正则表达式 BRE(Basic Regular Expression) grep, sed 默认使用 一些元字符(如 +, ?, {})需要反斜杠转义
扩展正则表达式 ERE(Extended Regular Expression) egrep, grep -E, sed -E, awk 更多元字符直接使用,不需要反斜杠

🧠 二、区别核心总结一句话

基本正则(BRE) 里,+, ?, {}, |, () 等特殊符号 默认是普通字符,必须加反斜杠才能生效

扩展正则(ERE) 里,这些符号 直接是特殊符号,不需要反斜杠


📘 三、举例对比:BRE vs ERE

功能 基本正则(BRE) 扩展正则(ERE) 说明
匹配一个或多个 a a\+ a+ + 在 BRE 需转义
匹配零个或一个 a a\? a? ? 在 BRE 需转义
匹配 2~4 个 a a\{2,4\} a{2,4} {} 在 BRE 需转义
匹配 "abc" 或 "xyz" `abc xyz` abc|xyz
捕获分组 \(ab\) (ab) () 在 BRE 需转义

🧪 四、实战示例对比

假设有文件 test.txt 内容:

复制代码
abc
aaa
ab
xyz

① 基本正则(默认 grep)

bash 复制代码
grep 'a\+' test.txt

✅ 匹配含一个或多个 a 的行。

bash 复制代码
grep 'a+' test.txt

❌ 错误,因为在 BRE 中 + 被当作普通字符。


② 扩展正则(grep -E 或 egrep)

bash 复制代码
grep -E 'a+' test.txt

✅ 正确,匹配一个或多个 a。

bash 复制代码
grep -E 'a\+' test.txt

❌ 错误,因为在 ERE 中 \+ 等价于 "匹配字符 +"。


⚙️ 五、与命令工具的关系

命令 默认使用 启用扩展正则方式
grep 基本正则(BRE) grep -Eegrep
sed 基本正则(BRE) sed -E
awk 扩展正则(ERE) 默认就是扩展正则,无需 -E
grep -P PCRE(Perl Compatible Regex) 支持更复杂的语法(如 \d, (?= )

🧩 六、易混点说明

场景 原因 解决方案
grep "a{2}" file 报错 在 BRE 中 {} 非特殊符号 grep "a\{2\}" file
grep -E "a{2}" file 正常 扩展正则允许 {} 无需转义
sed "s/a\+/b/g" 正常? 取决于 sed 版本 GNU sed -E 推荐使用
awk '/a+/' file 正常 awk 默认使用扩展正则

🧬 七、思维导图总结

复制代码
正则表达式体系
├── 基本正则(BRE)
│   ├── 命令:grep, sed
│   ├── 特性:+ ? { } ( ) | 需加 \
│   └── 示例:a\+, a\?, \(ab\)
│
└── 扩展正则(ERE)
    ├── 命令:grep -E, egrep, sed -E, awk
    ├── 特性:直接支持 + ? { } ( ) |
    └── 示例:a+, a?, (ab), a{2,4}, a|b

✅ 八、结论总结

项目 基本正则(BRE) 扩展正则(ERE)
常用命令 grep, sed grep -E, egrep, sed -E, awk
是否需加反斜杠 ✅ 是 ❌ 否
适合场景 兼容旧系统 日常推荐使用
推荐写法 grep -E + 不加反斜杠 ✅ 推荐现代写法

🔎 一句话总结:

在 Shell 正则中,"是否需要加反斜杠"取决于你使用的命令是否启用了扩展正则(ERE)。
grepsed 默认使用基本正则(需加 \),而 grep -Eawksed -E 使用扩展正则(不需 \)。


相关推荐
知星小度S24 分钟前
系统核心解析:深入文件系统底层机制——Ext系列探秘:从磁盘结构到挂载链接的全链路解析
linux
2401_8904430229 分钟前
Linux 基础IO
linux·c语言
智慧地球(AI·Earth)1 小时前
在Linux上使用Claude Code 并使用本地VS Code SSH远程访问的完整指南
linux·ssh·ai编程
老王熬夜敲代码2 小时前
解决IP不够用的问题
linux·网络·笔记
zly35003 小时前
linux查看正在运行的nginx的当前工作目录(webroot)
linux·运维·nginx
QT 小鲜肉3 小时前
【Linux命令大全】001.文件管理之file命令(实操篇)
linux·运维·前端·网络·chrome·笔记
问道飞鱼4 小时前
【Linux知识】Linux 虚拟机磁盘扩缩容操作指南(按文件系统分类)
linux·运维·服务器·磁盘扩缩容
egoist20234 小时前
【Linux仓库】超越命令行用户:手写C语言Shell解释器,解密Bash背后的进程创建(附源码)
linux·c语言·bash·xshell·环境变量·命令行参数·内建命令
Lenyiin4 小时前
《 Linux 修炼全景指南: 八 》别再碎片化学习!掌控 Linux 开发工具链:gcc、g++、GDB、Bash、Python 与工程化实践
linux·python·bash·gdb·gcc·g++·lenyiin
莲华君4 小时前
Bash Shell:从入门到精通
linux