正则表达式
注意要区别通配符 —— 正则一般配合字符提取命令,进行关键词精确匹配、过滤
概述
- 通配符在 Linux 中用来查询指定名称的文件名 —— 模糊查询
- 正则表达式则是对字符串和文件内容进行匹配 —— 精确查询
基础正则表达式
可结合 grep 行过滤命令实现精确匹配
基础正则表达式
元字符 | 作用 |
---|---|
* | 前一个字符匹配 0 次或任意多次 |
. | 匹配除了换行符外任意一个字符 |
^ | 匹配行首。例如 ^hello 会匹配以 hello 开头的行 |
$ | 匹配行尾。例如 hello$ 会匹配以 hello 结尾的行 |
[] | 匹配中括号中指定的任意一个字符,只匹配一个字符 |
[^] | 匹配除中括号的字符以外的任意一个字符,表示取反 |
\ | 转义符。用于取消特殊符号的作用 |
\{n\} | 表示前面的字符恰好出现 n 次 |
\{n,\} | 表示前面的字符出现不小于 n 次 |
\{n,m\} | 表示其前面的字符至少出现 n 次,最多出现 m 次 |
补充:在 vim 编辑器的命令模式中输入 “/^root” 搜索以 “root” 开头的行
元字符匹配
- “.” —— 匹配换行符以外的任意一个字符
- 正则表达式 “.” 只能匹配一个字符,但可以是任意字符
- “[]” —— 匹配中括号中任意一个字符,注意只能匹配一个字符
- 比如 [ao] 要么匹配一个 a 字符,要么匹配一个 o 字符
- [0-9]、[a-z]、[A-Z]、[a-Z] 类似都可以 —— 指定匹配的范围
- [^0-9] 匹配除了数字以外的任意一个字符
次数匹配 —— 字符数量
- “*” —— 前一个字符匹配任意多次
- 如果正则表达式写成 “aa*”,代表匹配至少包含有一个 a 的行
- “\?” —— 匹配前一个字符出现 0 次或者 1 次
- \{n\} —— 表示前面的字符恰好出现 n 次
- \{n,\} —— 表示其前面的字符出现不小于 n 次
- \{n,m\} —— 匹配其前面的字符出现不小于 n 次,最多出现 m 次
位置匹配
- “^” —— 匹配行首
- “$” —— 匹配行尾
- “^$” —— 匹配空白行
- [a-Z] —— 不以字母开头的行
整体匹配
- \(字符串\) —— 将括号内的内容当作一个整体
- (dog)* —— 用来匹配出现任意次数的 dog 字符串
- (dog)? —— 用来匹配 dog 字符串出现一次或者不出现
注:把多个字符当作一个整体用 “()” 括起
扩展正则表达式
扩展正则表达式
扩展元字符 | 作用 |
---|---|
+ | 前一个字符匹配 1 次或任意多次 |
? | 前一个字符匹配 0 次或 1 次 |
| | 匹配两个或多个分支选择,配合 () 使用 —— (|) |
() | 匹配其整体为一个字符,即模式单元。可以理解为多个单个字符组成的大字符 |
{} | 匹配前一个字符出现的次数 —— 自定义次数 |
注:正则表达式可以直接和 grep 结合使用,但扩展正则表达必须使用 grep -E 或 egrep 命令才能生效
扩展正则
- ? —— 匹配前一个字符出现或不出现,0 次或 1 次
- + —— 匹配前一个字符出现一次或任意次数,至少一次
- () —— 将括起来的字符串当作一个整体进行匹配
- | —— 分支匹配符号
- {} —— 匹配前一个字符出现次数(自定义次数)
- {n,m} —— 匹配前一个字符出现至少 n 次,最多 m 次 —— {0,1} = ?
- {n,} —— 匹配前一个字符出现至少 n 次,最多不设上限 —— {1,} = +、{0,} = *
- {n} —— 匹配一个字符出现 n 次的字符串
- {,m} —— 匹配前一个字符出现最多 m 次,最少不设下限
注:\{n,m\} —— 在标准正则中使用该符号时,需要用转义符
正则表达式练习
使用正则符号,对字符进行精确查询
-
编写一个文件,a.txt,对如下字符进行进行过滤测试
abcrootxyz root
-
使用 grep 命令对 “root” 进行过滤 —— 模糊查询
grep "root" /tmp/a.txt # 包含 "root" 的两行都会被输出
-
加入正则表达式,对 “root” 进行精确过滤 —— 精确匹配
grep "^root$" /tmp/a.txt # 加入 "^$",意味着只有 root 符合条件
说明:“^$” 表示开头结尾,是对字符精确的过滤,只有 “root” 符合条件,多一个字符都不符合条件
例1:编辑一个文件 b.txt,使用正则表达式进行字符过滤,测试
-
b.txt
abcrootzxc root # 空白行 # 前面是 tab,空格 root rooot roooot rooooooooooooooxcvxcvt rootrooot rt
-
“^$” —— 过滤空白行
grep -n "^$" /tmp/b.txt # 仅过滤出行号 4:,不包含任意字符
-
“.” —— 表示任意一个字符,注意仅表示一个字符
grep "r..t" /tmp/b.txt # root 两行符合条件都过滤输出 grep "r.t" /tmp/b.txt # . 仅能表示一个字符,不存在符合条件的字符
-
“[]” —— 中括号内可写字符范围,匹配符合条件的一个字符
grep -n "r[a-z][a-z]t" /tmp/b.txt # 两行 abcrootzxc、root 都符合条件 grep -n "r[a-z]t" /tmp/b.txt # [a-z] 仅能表示 a-z 的一个字符 grep -n "r[aoe][a-z]t" /tmp/b.txt # [aoe] 表示 a、o、e 其中一个字符
-
“*” —— 匹配前一个字符或字符串出现任意次数的一行 —— 包括 0 次
grep -n "r.*t" /tmp/b.txt # 输出任意字符开头任意数量的行,rt 同样符合条件
例2:扩展正则 —— 必须使用 grep -E,或 egrep 进行使用
-
? —— 匹配前一个字符出现或不出现,只能匹配一次
egrep -n "rooo?t" /tmp/b.txt
-
+ —— 匹配前一个字符出现一次或任意次数
egrep -n "rooo+t" /tmp/b.txt
-
{} —— 规定前面的字符出现次数
egrep -n "ro{2,3}t" /tmp/b.txt # 最少两次,最多三次,root、rooot egrep -n "ro{2,3}" /tmp/b.txt # 去掉 t,就会包含2个、3个、以及三个上,不规定t结尾 # 先判断是否包含 3个o,然后还会继续判断是否还包含 2个o,rootrooot也会符合条件
-
() —— 将括号内的字符当作一个整体,一个字符
cat /tmp/b.txt #--》rootrootroot \n rootroot egrep "(root){2}" /tmp/b.txt # 输出 rootroot、rootrootroot
-
| —— “r(o|x){4}t”,匹配出现四次 o 或四次 x 的字符串
egrep "r(o|x){4}t" /tmp/b.txt # 匹配 o或x 出现4次的字符串,o或x必须连续 egrep "ro|x{4}t" /tmp/b.txt # 必须加 () 才能当作整体进行匹配
补充
- 匹配手机号
- 匹配 ip
- 匹配邮箱
匹配 IP 地址
- x.x.x.x —— 范围 0-255,先想办法匹配其中一个 0-255
- 注意不能使用 egrep “[0-255]”,[0-255] 只能匹配出 0、1、2、5 这四个数字
思路
-
从个位数 --》到双位数 --》再到三位数 --》三位数再细分范围
-
0-9、10-99、100-199、200-249、250-255
-
[0-9]、[1-9][0-9]、1[0-9][0-9]、2[0-4][0-9]、25[0-5]
egrep "^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$" num.txt #匹配一个255
注:“[]” 中只能表示单个字符的范围,所以不能直接使用 “[0-255]” 的方式去过滤 IP 地址,需要按每一位的数字进行细分
实现
-
写一个文件 —— ip.txt
a.b.c.d a.192.168.88.110 192.168.47.1 0.0.0.0 255.255.255.255 300.300.300.300
-
代码实现过滤,匹配 —— “^(x)(.x){3}$”
egrep "^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$" /tmp/ip.txt
注:实际一般只需要过滤到某个网段而已,不必四位数都写