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 -E 或 egrep

扩展正则支持更多符号:

符号 含义 示例 说明
+ 前项至少出现一次 a+b 匹配 ab、aab 重复匹配
? 前项可有可无 colou?r 匹配 color 或 colour 可选项
` ` 或关系 `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

✅ 优点:无需 grep、sed 等外部命令

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


🔍 九、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 是什么?

sed(stream 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

匹配 cat 或 dog 并替换为 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 -E 或 egrep
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)。
grep、sed 默认使用基本正则(需加 \),而 grep -E、awk、sed -E 使用扩展正则(不需 \)。


相关推荐
2035去旅行6 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
陈希1237 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡8 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
且从容.11 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道12 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.15 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落16 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨16 小时前
WSL2的安装与使用
linux·wsl
微小的鱼16 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng17 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器