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 使用扩展正则(不需 \)。


相关推荐
爱吃甜品的糯米团子3 小时前
Linux 学习笔记之进程管理、网络基础与常用软件安装
linux·网络·学习
Micro麦可乐3 小时前
Centos Stream 9 中Docker安装出现 download.docker.com:443 的问题解决
linux·docker·centos·podman
poemyang3 小时前
你的程序为何卡顿?从LINUX I/O三大模式寻找答案
linux·rpc
---学无止境---4 小时前
Linux中早期控制台初始化和注册的实现
linux
撬动未来的支点4 小时前
DMABUF 核心概念:Linux 的“共享白板”机制
linux
今麦郎xdu_5 小时前
【Linux系统】命令行参数和环境变量
linux·服务器·c语言·c++
还不秃顶的计科生5 小时前
linux下conda未安装的解决方法(离线安装linux下的conda)
linux·运维·服务器
DeeplyMind5 小时前
Linux的Dynamic debug功能
linux·dynamic debug
LJ-SEU5 小时前
win-ubuntu网络转发
linux·网络·ubuntu