正则表达式
什么是正则表达式?
正则表达式(Regular Expression,简称 regex 或 regexp)是一种描述字符串模式的语法。它用于文本搜索、匹配、替换等操作,是 Linux 文本处理的核心技能。
正则表达式类型
Linux 中有两种主要的正则表达式:
| 类型 | 说明 | 支持工具 |
|---|---|---|
| BRE | 基本正则表达式 | grep、sed |
| ERE | 扩展正则表达式 | egrep、grep -E、sed -E |
主要区别
| 元字符 | BRE | ERE |
|---|---|---|
? | \? | ? |
+ | \+ | + |
{} | \{\} | {} |
() | \(\) | () |
| ` | ` | | |
基本元字符
字符匹配
| 元字符 | 说明 | 示例 |
|---|---|---|
. | 任意单个字符 | a.c 匹配 abc、adc |
[] | 字符类 | [abc] 匹配 a、b、c |
[^] | 否定字符类 | [^abc] 匹配非 a、b、c |
\ | 转义字符 | \. 匹配点号 |
字符类简写
| 元字符 | 说明 |
|---|---|
[0-9] | 数字 |
[a-z] | 小写字母 |
[A-Z] | 大写字母 |
[a-zA-Z] | 所有字母 |
[a-zA-Z0-9] | 字母和数字 |
POSIX 字符类
| 字符类 | 说明 |
|---|---|
[:alnum:] | 字母和数字 |
[:alpha:] | 字母 |
[:digit:] | 数字 |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:space:] | 空白字符 |
[:punct:] | 标点符号 |
[:blank:] | 空格和 Tab |
bash
# 使用 POSIX 字符类
$ grep '[[:digit:]]' file.txt
$ grep '[[:alpha:]]' file.txt位置锚点
| 元字符 | 说明 | 示例 |
|---|---|---|
^ | 行首 | ^hello |
$ | 行尾 | world$ |
\b | 单词边界 | \bword\b |
\B | 非单词边界 | \Bword\B |
bash
# 匹配以 hello 开头的行
$ grep '^hello' file.txt
# 匹配以 world 结尾的行
$ grep 'world$' file.txt
# 匹配整行
$ grep '^hello world$' file.txt
# 匹配空行
$ grep '^$' file.txt
# 匹配完整单词
$ grep '\bword\b' file.txt重复限定符
| 元字符 | 说明 | 示例 |
|---|---|---|
* | 零次或多次 | ab*c 匹配 ac、abc、abbc |
+ | 一次或多次 | ab+c 匹配 abc、abbc |
? | 零次或一次 | ab?c 匹配 ac、abc |
{n} | 正好 n 次 | a{3} 匹配 aaa |
{n,} | 至少 n 次 | a{2,} 匹配 aa、aaa... |
{n,m} | n 到 m 次 | a{2,4} 匹配 aa、aaa、aaaa |
bash
# 基本使用
$ grep 'ab*c' file.txt # BRE
$ grep -E 'ab+c' file.txt # ERE
# 指定次数
$ grep 'a\{3\}' file.txt # BRE
$ grep -E 'a{3}' file.txt # ERE
# 范围
$ grep -E 'a{2,4}' file.txt分组和捕获
bash
# 分组
$ grep -E '(ab)+' file.txt # 匹配 ab、abab、ababab
# 后向引用
$ grep -E '(.).\1' file.txt # 匹配 aba、aca 等
# sed 中使用
$ sed 's/\(hello\) \(world\)/\2 \1/' file.txt
# ERE
$ sed -E 's/(hello) (world)/\2 \1/' file.txt交替(或)
bash
# 使用 |
$ grep -E 'cat|dog' file.txt
# 与分组组合
$ grep -E '(red|blue) car' file.txt常用模式示例
数字
bash
# 整数
[0-9]+
\d+
# 浮点数
[0-9]+\.[0-9]+
# 正负数
-?[0-9]+字符串
bash
# 引号字符串
"[^"]*"
'[^']*'
# 任意单词
\b\w+\b常见格式
bash
# Email
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
# URL
https?://[^\s]+
# IP 地址(简化)
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
# 日期 YYYY-MM-DD
[0-9]{4}-[0-9]{2}-[0-9]{2}
# 时间 HH:MM:SS
[0-9]{2}:[0-9]{2}:[0-9]{2}
# 电话号码(中国手机)
1[3-9][0-9]{9}grep 中使用正则
bash
# 基本正则
$ grep 'pattern' file.txt
# 扩展正则
$ grep -E 'pattern' file.txt
$ egrep 'pattern' file.txt
# Perl 正则
$ grep -P 'pattern' file.txt
# 只匹配完整单词
$ grep -w 'word' file.txt
# 显示匹配部分
$ grep -o 'pattern' file.txt
# 忽略大小写
$ grep -i 'pattern' file.txt
# 反向匹配
$ grep -v 'pattern' file.txt实例
bash
# 查找包含数字的行
$ grep '[0-9]' file.txt
# 查找以字母开头的行
$ grep '^[a-zA-Z]' file.txt
# 查找 email 地址
$ grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' file.txt
# 查找 IP 地址
$ grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' file.txt
# 查找空行或只有空白的行
$ grep -E '^[[:space:]]*$' file.txtsed 中使用正则
bash
# 基本替换
$ sed 's/old/new/g' file.txt
# 使用扩展正则
$ sed -E 's/pattern/replacement/g' file.txt
# 后向引用
$ sed 's/\([a-z]\+\) \([a-z]\+\)/\2 \1/' file.txt
$ sed -E 's/([a-z]+) ([a-z]+)/\2 \1/' file.txt
# 使用 & 引用整个匹配
$ sed 's/[0-9]\+/【&】/g' file.txt实例
bash
# 删除 HTML 标签
$ sed 's/<[^>]*>//g' file.html
# 删除行首空白
$ sed 's/^[[:space:]]*//' file.txt
# 提取引号内容
$ sed -E 's/.*"([^"]*)".*/\1/' file.txt
# 格式化电话号码
$ sed -E 's/([0-9]{3})([0-9]{4})([0-9]{4})/\1-\2-\3/' file.txtawk 中使用正则
bash
# 模式匹配
$ awk '/pattern/' file.txt
# 字段匹配
$ awk '$1 ~ /pattern/' file.txt
$ awk '$1 !~ /pattern/' file.txt
# 使用正则分隔符
$ awk -F '[,:]' '{print $1}' file.txt
# gsub 替换
$ awk '{gsub(/pattern/, "replacement"); print}' file.txt实例
bash
# 打印包含数字的行
$ awk '/[0-9]/' file.txt
# 打印第一列是数字的行
$ awk '$1 ~ /^[0-9]+$/' file.txt
# 提取 email
$ awk 'match($0, /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/) {print substr($0, RSTART, RLENGTH)}' file.txt贪婪与非贪婪
默认情况下,正则表达式是贪婪的,会尽可能多地匹配。
bash
# 贪婪匹配
$ echo "aaa bbb ccc" | grep -oE 'a.*c'
aaa bbb ccc
# 非贪婪匹配(Perl 正则)
$ echo "aaa bbb ccc" | grep -oP 'a.*?c'
aaa bbb c常见技巧
匹配不包含某字符串的行
bash
# 使用 -v 选项
$ grep -v 'pattern' file.txt
# 使用负向断言(Perl 正则)
$ grep -P '^(?!.*pattern)' file.txt匹配多行
bash
# sed 中匹配多行
$ sed -n '/start/,/end/p' file.txt
# awk 中匹配多行
$ awk '/start/,/end/' file.txt转义特殊字符
需要转义的特殊字符:. * + ? ^ $ [ ] { } ( ) | \
bash
# 匹配点号
$ grep '\.' file.txt
# 匹配方括号
$ grep '\[' file.txt
# 匹配反斜杠
$ grep '\\' file.txt正则表达式测试工具
在线工具
- regex101.com
- regexr.com
命令行测试
bash
# 使用 grep 测试
$ echo "test string" | grep -E 'pattern'
# 使用 sed 测试
$ echo "test string" | sed -E 's/pattern/replacement/'
# 使用 awk 测试
$ echo "test string" | awk '/pattern/'常见错误
1. 忘记转义
bash
# 错误:. 匹配任意字符
$ grep 'file.txt' file.txt
# 正确
$ grep 'file\.txt' file.txt2. BRE 和 ERE 混淆
bash
# BRE 中 + 需要转义
$ grep 'a\+' file.txt
# ERE 中不需要
$ grep -E 'a+' file.txt3. 贪婪匹配导致意外结果
bash
# 可能匹配过多
$ sed 's/<.*>//' file.html
# 使用否定字符类
$ sed 's/<[^>]*>//' file.html小结
本章介绍了 Linux 正则表达式:
- 元字符:
.、*、+、?、^、$等 - 字符类:
[]、[^]、POSIX 类 - 量词:
{n}、{n,}、{n,m} - 分组和引用:
()、\1 - 在各工具中使用:grep、sed、awk
正则表达式是一项需要练习的技能。从简单的模式开始,逐步掌握更复杂的用法。
上一章:文本处理工具
下一章:用户管理