作用:在Linux操作系统中,Shell正则表达式可以用于复杂数据处理(检索、替换、删除)。
tr、grep、sed、awk都支持正则表达式!!!
1. 正则表达式
正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
注意:正则表达式是一个独立的语言,不仅可以在Shell脚本中使用,在Python中也可以使用
Shell:数据检索、数据处理
Python:数据检索、爬虫技术
2. 应用场景
① 数据验证(表单验证、如手机、邮箱、IP地址)
② 数据检索(数据检索、数据抓取)
③ 数据过滤(敏感词过滤)=> 论坛、小说 => 要求 => 北京/上海 => 帝都
…
3. 正则表达式详解(重点)
正则表达式分为两部分内容:① 普通字符匹配 ② 正则匹配符匹配
普通匹配
普及:/proc/cpuinfo获取服务器的CPU信息!
#!/bin/bash
# 提取 CPU 型号
grep "model name" /proc/cpuinfo | uniq
# 提取 CPU 核心数
grep "cpu cores" /proc/cpuinfo | uniq
正则匹配
[0-9] : 匹配0-9之间的任一某个数字
[a-z] : 匹配a-z之间任意的某个字母
案例1:匹配数字3
echo "abc123" |grep "3"
案例2:匹配这个字符串中的所有数字
echo "abc123" |grep "[0-9]"
案例3:匹配这个字符串中所有的字母
echo "abc123" |grep "[a-z]"
grep选项-E 和 -P区别:
普通用法:grep 关键词 字符串
正则用法:
grep -E 正则表达式 字符串
grep -P 正则表达式 字符串
-E (Extended Regular Expressions, 扩展正则表达式)
扩展正则表达式
-E选项启用了 扩展正则表达式(ERE),它比标准的基本正则表达式(BRE)支持更多的功能,例如:
使用 +(表示一个或多个)、?(表示零个或一个)、|(表示或)等元字符时,不需要加反斜杠(\)进行转义。
支持括号 () 和竖线 | 等用于分组和选择的功能。
-P选项启用了 Perl 兼容正则表达式(PCRE),它支持更强大、更复杂的正则表达式功能,包括一些扩展的功能,例如:
支持一些在 -E 中不支持的功能,例如 \d,\w,\b(单词边界)等
正则表达式的语法更接近 Perl
使用原则:我一般优先使用-E,如果遇到\d、\w、\s的时候才会使用-P;如果正则表达式正确,但是-E匹配不到内容,尝试使用-P!!!
正则工具箱:https://goldtools.cn/regexp
正则匹配三步走:① 查什么 ② 查多少 ③ 从哪查
☆ 查什么(元字符)
| 代码 | 功能 |
| .(我是一个英文状态下点号.) | 万能字符,匹配任意1个字符(除了\n) |
| [ ] | 匹配[ ]中列举的字符,字符簇,本身表示一个范围区间,每次只能匹配其中的某个字符 |
| [^指定字符] | 匹配除了指定字符以外的所有字符,^托字节在字符簇中出现代表取反的意思 |
| \d | 匹配数字,即[0-9],\d都称之为Perl风格语法 |
| \D | 匹配非数字,即不是数字 |
| \s | 匹配空白,即 空格,tab键 |
| \S | 匹配非空白 |
| \w | 匹配非特殊字符,即a-z、A-Z、0-9、_ |
| \W | 匹配特殊字符,即非字母、非数字、非下划线 |
[a-z]匹配26个小写字符中的任一一个,[A-Z]匹配26个大写字符中的任一一个,[0-9]任一某个数字,[3-9]匹配3-9之间的任一某个数字,[aeiou]匹配小aeiou五个字符中的任一一个
[^a-z] :匹配除了26个小写字母以外的任一某个字符,[^0-9] :匹配除数字以外的任一字符
^托字节如果出现在[]字符簇中,则代表取反的含义;如果出现在[]字符簇外侧,则代表以某些内容开头!
案例1:查找包含小写字母的行
grep "[a-z]" file.txt
结论:grep命令,默认是按行进行匹配,实际上Shell三剑客(grep、sed、awk)都是按行匹配!
案例2:匹配包含ERROR关键字的行
grep ERROR /var/log/mysqld.log
案例3:查找当前目录中包含数字的文件名
#!/bin/bash
# 查找包含数字的文件名
ls | grep -E "[0-9]"
其他演示:
echo "abc123" |grep '[0-9]'
echo "abc123" |grep -P '\w' # \w既包含字母、又包含数字还包含下划线
echo "abc123" |grep -E '[0-9a-zA-Z]'
echo "abc.123" |grep -E '.' # 万能字符
echo "abc.123" |grep -E '\.' # 匹配.点号
echo "abc123" |grep -E '[^0-9]'
echo "abc 123" |grep -P '\s' # 匹配空格
echo "abc 123" |grep -P '\S' # 匹配非空格
小结:
在实际工作中,元字符主要用于匹配我们想要的字符。
☆ 查多少(匹配符)
注意:它只能匹配前一个字符出现次数
| 代码 | 功能 |
| * | 匹配前一个字符出现0次或者无限次,即可有可无,简称0到多 |
| + | 匹配前一个字符出现1次或者无限次,即至少有1次,简称1到多 |
| ? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有,简称0或1 |
| {m} | 匹配前一个字符出现m次,{3},匹配前一个字符只能出现3次 |
| {m,} | 匹配前一个字符至少出现m次,{3,},匹配前一个字符至少出现3次,相当于3到多 |
| {m,n} | 匹配前一个字符出现从m到n次,{3,5},匹配前一个字符至少出现3次,至多出现5次 |
重点记住前4个,* + ? {m}
如果不确定要匹配内容的多少,也不确定具体要匹配什么内容,而是匹配所有内容。
特殊写法 => .* 匹配任何内容
<body></body>
<body>hello world</body>
<body>...............................<body>
正则可以编写为:<body>(.*)</body>
正则表达式中,有一个匹配原则(贪婪匹配):默认情况下,正则能匹配多的就不会匹配少的,我们把这种特性称之为贪婪匹配!!!
普及一个概念:Nginx软件一共有两个日志(access.log访问日志) + (error.log错误日志)
access.log:客户端 =》Nginx =》服务器端发起访问,都是走HTTP协议/HTTPS协议
HTTP协议:传统协议,数据传输是非加密传输,有安全隐患 => 80端口
HTTPS协议:安全传输协议,S(Secure安全 或这 SSL证书 => 互联网组织给网站颁发认证证书),加密传输,不存在安全隐患 => 443端口
网络钓鱼:就是开发一个和真实网站一模一样的站点,没有互联网颁发的SSL证书(自己申请,每次申请可以免费使用3个月 + 购买1万多1年)
HTTP协议方法一般有两种:GET(获取,读取网页内容) + POST(登录,发送内容给服务器)
LNMT => Nginx => Tomcat(故障)=> 500
案例1:从日志文件中提取所有包含 IP 地址的行。IP 地址是数字和点号的组合,类似 192.168.0.1
. :万能字符,代表匹配除了\n以外的所有字符
\. :非万能字符,只能匹配.点号;\代表转义字符
192.168.1.1 - - [07/Jan/2025:12:45:32 +0000] "GET /index.html HTTP/1.1" 200 1024
172.16.0.2 - - [07/Jan/2025:12:46:15 +0000] "POST /login HTTP/1.1" 403 2048
192.168.2.3 - - [07/Jan/2025:12:47:22 +0000] "GET /about.html HTTP/1.1" 200 1024
10.0.0.4 - - [07/Jan/2025:12:48:44 +0000] "GET /contact.html HTTP/1.1" 404 512
invalid_ip - - [07/Jan/2025:12:49:55 +0000] "GET /invalid HTTP/1.1" 400 0
#!/bin/bash
# 定义日志文件
LOGFILE="/var/log/access.log"
# 使用正则表达式提取包含IP地址的行
grep -P "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" $LOGFILE
案例2:查找日志文件中日期格式为 YYYY-MM-DD 的记录,确保年份部分有 4 位数字,日期部分格式正确。
application.log
2025-01-01 应用启动
2025-01-02 用户登录
Error: 无法连接数据库
2025-01-03 数据导入成功
系统错误发生在2025-01-04
用户退出
#!/bin/bash
# 定义日志文件
LOGFILE="/var/log/application.log"
# 匹配日期格式 YYYY-MM-DD
grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2}" $LOGFILE
案例3:提取邮件地址
xxx@xxx.com
xxx@xxx.com.cn
邮箱名称:一般是字母、数字、下划线、横岗、点号
@:中间必须要有@符号
结尾:都是公司域名,如baidu.com、sina.com.cn、itcast.cn等等
file_with_emails.txt
valid.email@example.com
another.email@domain.org
invalid-email.com
yet.another.email@sub.domain.co.uk
123@numbers.com
missingatsign.com
email@valid-domain.com
not_a_valid_email@com
#!/bin/bash
# 定义包含邮件地址的文件
EMAIL_FILE="file_with_emails.txt"
# 提取邮件地址并输出
grep -E "[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" $EMAIL_FILE
注意:如果
.点号出现在[]字符簇中,则不需要\反斜杠转义,就代表点号普通字符。
注意:如果在[]字符簇同时出现了点号、下划线以及横岗,由于-是特殊字符,必须按照以下顺序摆放._-,否则会有语法错误
案例4:从库存文件中提取所有符合产品编号格式(如 "P12345"、"A7890")的记录
前置内容:\b单词边界,如A123 产品A,匹配 A123 产品A,A123两边就属于单词边界
I am Tom
\bTom\b
stock.txt
A123 产品A
B4567 产品B
C890 产品C
D12 产品D
XYZ123 产品E
A 1234 产品F
#!/bin/bash
# 定义库存文件路径
STOCKFILE="/data/stock.txt"
# 提取产品编号
grep -P "\b[A-Z][0-9]+\b" $STOCKFILE
\b:代表边界,以上就是就代表字符必须和数字连在一起,两边可以有空格但是中间必须连续
小结:
匹配符就是用于匹配前面一个字符出现多少次!!!
☆ 从哪查(定位符)
| 代码 | 功能 |
| ^ | 托字节,匹配字符串开头,^/dev:匹配以/dev开头的行 |
| $ | 匹配字符串结尾 |
引入一个案例:用正则表达式匹配电话号码(只要11位合法、合理)
合法:
1
3、4、5、6、7、8、9
后面9位有没有要求?只要[0-9]之间
echo "13575668799" |grep -E "^1[3-9][0-9]{9}$"
案例1:检查 /etc/passwd 文件中是否有用户账户的名称以特定字符(如 "admin")开头
提前创建用户:useradd admin123
#!/bin/bash
# 检查 /etc/passwd 中以 "admin" 开头的账号
grep -E '^admin.*' /etc/passwd
案例2:去除配置文件中的注释以及空行(重点)
前置:
正则表达式1 | 正则表达式2
|:在正则中代表或的含义,如果是正则匹配,则代表既要匹配表达式1 还要匹配表达式2
#!/bin/bash
# 定义配置文件
CONFIG_FILE="/etc/rsyslog.conf"
# 去除文件中以注释开头的行或者空行
grep -Ev "^#|^$" $CONFIG_FILE
或
egrep -v "^#|^$" $CONFIG_FILE
在正则中,egrep命令等价于grep -E
4. 分组、捕获、反向引用(重点)
作用:主要是进行重复数据的匹配操作
举个栗子:1234-1111-1221-3333
在之前的匹配中,我们只能匹配连续的4位数字,如\d{4}或[0-9]{4}
要求:要求使用正则匹配1111以及3333这种格式的数字(特点:匹配4位连续相同的数字,内容完全相同)
要求:要求使用正则匹配1221这种格式的数字(特点:第1位和第4位内容相同,第2位和第3位内容相同)
☆ 分组
在正则表达式中,通过一对圆括号括起来的内容,我们就称之为"分组"。
\d\d\d:匹配连续的3位数字
\d(\d)(\d) :正则表达式中\d\d\d中,(\d)(\d)就是分组(子表达式),一共有两个()圆括号,则代表两个分组
☆ 捕获
当正则表达式在字符串中匹配到相应的内容后,计算机系统会自动把分组所匹配的到内容放入到系统的对应缓存区中(缓存区从$1开始)
☆ 反向引用
在正则表达式中,我们可以通过\n(n代表第n个缓存区的编号)来引用缓存区中的内容,我们把这个过程就称之为"反向引用"。

案例1:
① 查找连续的四个数字,如:3569
答:[0-9]{4}或\d{4}
② 查找连续的相同的四个数字,如:1111
答:(\d)\1\1\1
③ 查找数字,如:1221,3443
答:(\d)(\d)\2\1
④ 查找字符,如:AABB,TTMM(提示:A-Z,正则:[A-Z])
答:([A-Z])\1([A-Z])\2
⑤ 查找连续相同的四个数字或四个字符(提示:\w)
答:(\w)\1\1\1
注:以上都是Perl风格写法,grep必须配合-P使用
小结:
作用:主要是进行重复数据的匹配操作
有几个小括号就有几个分组,执行顺序都是从左向右 => (\d)(\d)