- A+
正则表达式介绍与基础
正则表达式(Regular Expression)是一个定义搜索模式的字符序列。
在做文字处理或编写程序时,若需要用到查找、替换等功能时,可以使用正则表达式来简单便捷地完成目标。
简单而言,正则表达式通过使用一些特殊符号,使得使用者可以方便轻松地实现查找、删除、替换等功能。
Vi 中经常会使用到正则表达式,为了充分发挥 shell 编程的威力,Linux 使用者需要精通正则表达式。
首先是正则表达式的特殊符号:
[:alnum:]代表英文大小写字母及数字 [:alpha:]代表英文大小写字母 [:blank:]代表空格和 tab 键 [:cntrl:]键盘上的控制按键,如 CR,LF,TAB,DEL [:digit:]代表数字 [:graph:]代表空白字符以外的其他 [:lower:]小写字母 [:print:]可以被打印出来的任何字符 [:punct:]代表标点符号 [:upper:]代表大写字母 [:space:]任何会产生空白的字符如空格,tab,CR 等 [:xdigit:]代表 16 进位的数字类型
特殊符号实例
在 WebIDE 中使用 touch 命令或图形界面新建一个 .txt 文件并将下文中的文本内容复制进去。
touch regular_express.txt
也可以使用 wget 指令从本节开头的实验环境说明处下载,这两种方式取得的文件是一样的。
文本内容为:
"Open Source" is a good mechanism to develop programs. apple is my favorite food. Football game is not use feet only. this dress doesn't fit me. However, this dress is about $ 3183 dollars. GNU is free air not free beer. Her hair is very beauty. I can't finish the test. Oh! The soup taste good. motorcycle is cheap than car. This window is clear. the symbol '*' is represented as start. Oh!My god! The gd software is a library for drafting programs. You are the best is mean you are the no. 1. The world <Happy> is the same with "glad". I like dog. google is the best tools for search keyword. goooooogle yes! go! go! Let's go. # I am VBird
使用特殊符号查找小写字母:
grep -n '[[:lower:]]' regular_express.txt
红色为匹配成功的字符。
使用特殊符号查找数字:
grep -n '[[:digit:]]' regular_express.txt
grep命令与正则表达式
查找特定字符串
参数说明:
- -a :以 text 档案的方式搜寻 binary 档案数据
- -c :计算找到 '搜寻字符串' 的次数
- -i :忽略大小写的不同,所以大小写视为相同
- -n :顺便输出行号
- -v :反向选择,亦即显示没有 '搜寻字符串' 内容的行
grep -n 'the' regular_express.txt grep -in 'the' regular_express.txt
反向查找,当该行没有字符串'the'时才显示在屏幕上。
grep -vn 'the' regular_express.txt
字符组匹配
[ ] 可以用来查找字符组。
值得注意的是,无论 [ ] 中包含多少个字符,它都只代表一个字符。比如说,我们想要查找 tast 或者 test 这两个字符串,注意到二者的拼写大部分相同,都是 t?st 的形式,故此时可以使用 [ ] 进行查找:
grep -n 't[ae]st' regular_express.txt
字符组支持使用连字符 - 来表示一个范围。当 - 前后构成范围时,要求前面字符的码位小于后面字符的码位。
[^] 为反向选择字符组,用于排除后面的字符,使用方式为 [^...]。
需要注意 [^] 与参数 -v 的区别,尽管二者都表示反向选择,但是如果包含有反向选择的字符的行含有其他字符的话,[^] 仍会输出该行,而 -v 则只会输出不含有反向选择的字符的行。
下面给出一些应用示例:
[abc] :表示 “a” 或 “b” 或 “c” [0-9] :表示 0~9 中任意一个数字,等价于 [0123456789] [u4e00-u9fa5] :表示任意一个汉字 [^a1<] :表示除 “a”、“1”、“<” 外的其它任意一个字符 [^a-z] :表示除小写字母外的任意一个字符
使用 - 和 [^] 查找 Xoo 形式的字符串,要求 oo 之前不能包含小写字母:
grep -n '[^a-z]oo' regular_express.txt
回忆前一节所提到的正则表达式特殊符号,[:lower:] 表示小写字母,因此也可以使用
grep -n '[^[:lower:]]oo' regular_express.txt
这两者是等价的,但是可以看出,使用[a-z]来表示小写字母明显更加便捷,也更加灵活。
查找字符 oog。
grep -n 'oog' regular_express.txt
如果我不想要 oog 字符前面有 g,则使用 [^g]oog。
grep -n '[^g]oog' regular_express.txt
同理,若不想让字符 oog 前面为 g 或者 o,则使用 [^go]oog。
grep -n '[^go]oog' regular_express.txt
其中
grep -n '[^go]oog' regular_express.txt
返回结果为空,表示没有匹配到符合要求的字符串。
行首符 ^ 与行尾符 $
在第一个实验中,我们使用
grep -n 'the' regular_express.txt
查找含有 the 的字符串,如果你只想查找行首为 the 的字符行,则使用以下命令:
grep -n '^the' regular_express.txt
查找行首为大写字母的所有行:
grep -n '^[A-Z]' regular_express.txt
注意行首符 ^ 和反向选择 [^] 的区别,^[A-Z] 表示以大写字母开头。[^A-Z] 表示除了大写字母 A-Z 的所有字符。
行尾符 $ 的用法与行首符类似。
查找以字母 d 结尾的行:
grep -n 'd$' regular_express.txt
这里有一个小技巧,将行首符与行尾符连用,可以用来查找空行:
grep -n '^$' regular_express.txt
应用实例
查看 /etc/insserv.conf 文档
^$: 过滤掉空白行
^#: 过滤掉注释行(以 # 号开头)
cat -n /etc/insserv.conf grep -v '^$' /etc/insserv.conf | grep -v '^#'
任意一个字符 . 与重复字符 *
查找 a?ou? 类型的字符:
grep -n 'a.ou.' regular_express.txt
其中小数点表示任意一个字符,一个小数点只能表示一个未知字符。
*(星号):代表重复前面 0 个或者多个字符。 e*: 表示具有空字符或者一个以上 e 字符。 ee*,表示前面的第一个 e 字符必须存在。第二个 e 则可以是 0 个或者多个 e 字符。 eee*,表示前面两个 e 字符必须存在。第三个 e 则可以是 0 个或者多个 e 字符。 ee*e :表示前面的第一个与第三个 e 字符必须存在。第二个 e 则可以是 0 个或者多个 e 字符。
下面的第一条命令与第二条命令由于允许存在空字符,所以会打印所有文本。
grep -n 'e*' regular_express.txt grep -n '@*' regular_express.txt grep -n 'eee*' regular_express.txt
限定连续字符范围 { }
{ } 可限制一个范围区间内的重复字符数。如果现在要求找出存在连续的两个 o 字符的字符串,根据前面所学的知识,我们可以使用:
grep -n 'ooo*' regular_express.txt
另一种方式是使用 { }。由于 { 与 } 在 shell 中有特殊意义,故在使用时需要用到转义字符 。
查找连续的两个 o 字符:
grep -n 'o{2}' regular_express.txt
查找 g 后面接 2 到 5 个 o,然后再接 g 的字符串:
grep -n 'go{2,5}g' regular_express.txt
总结:
^word 表示待搜寻的字符串(word)在行首 word$ 表示待搜寻的字符串(word)在行尾 .(小数点) 表示 1 个任意字符 表示转义字符,在特殊字符前加 会将特殊字符意义去除 * 表示重复 0 到无穷多个前一个 RE(正则表达式)字符 [list] 表示搜索含有 l,i,s,t 任意字符的字符串 [n1-n2] 表示搜索指定的字符串范围,例如 [0-9] [a-z] [A-Z] 等 [^list] 表示反向字符串的范围,例如 [^0-9] 表示非数字字符,[^A-Z] 表示非大写字符范围 {n,m} 表示找出 n 到 m 个前一个 RE 字符 {n,} 表示 n 个以上的前一个 RE 字符
sed命令与正则表达式
sed 是非交互式的编辑器。它不会修改文件,除非使用 shell 重定向来保存结果。默认情况下,所有的输出行都会被打印到屏幕上。
sed 编辑器逐行处理文件(或输入),并将结果打印到屏幕上。
具体过程如下:首先 sed 把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。
sed 每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed 便结束运行。sed 把每一行都存在临时缓冲区中,对这个副本进行编辑,所以直接使用不会修改原文件内容。
如果要修改原文件,需要添加 -i 选项。
输出文件内容
将 regular_express.txt 的内容列出并打印行号,并将 2-5 行删除显示:
nl regular_express.txt | sed '2,5d'
2,5d 表示删除 2~5 行,d 即为 delete。
同理,删除第 2 行:
nl regular_express.txt | sed '2d'
删除第三行到最后一行, $ 表示定位到最后一行:
nl regular_express.txt | sed '3,$d'
使用 -i 在原文件中删除第 1 行:(注意:该指令会修改原文件)
sed -i '1d' regular_express.txt
使用 a 和 i 新增输出
在第二行后添加字符串 test:
nl regular_express.txt | sed '2a test'
在第二行前添加字符串 test:
nl regular_express.txt | sed '2i test'
在第二行后添加两行 test,n 表示换行符:
nl regular_express.txt | sed '2a testntest'
行内容替换
将 2-5 行的内容替换为 No 2-5 number,c 为替换内容选项:
nl regular_express.txt | sed '2,5c No 2-5 number'
输出指定行
输出 regular_express.txt 的第 5-7 行,其中 -n 为安静模式选项,我们在前面的章节中已经介绍过。
执行以下两条命令可以明显看出区别:
nl regular_express.txt |sed -n '5,7p' nl regular_express.txt |sed '5,7p'
字符串替换
格式为:sed 's/lodstr/newstr/g'
来看一个实例。首先查看本机 IP 地址:
ifconfig eth0
字段inet 地址:192.168.x.x即为本机的 IP 地址,这是经由 NAT 转换后分配的内网 IP 地址,在此不做展开。
之后使用 grep 指令在 ifconfig eth0 的结果中查找 inet,并打印至终端:
ifconfig eth0 | grep 'inet'
可以使用字符串替换功能将 IP 前面的部分予以删除,按照思路,也就是将 inet 地址: 替换为空字符串,可以简单写成:
ifconfig eth0 | grep 'inet '| sed 's/inet 地址://g'
(注意中文字符不能直接复制,需要自己在终端输入)
但正则表达式在实际应用中可以非常灵活,回想一下我们在前两节所学的关于正则表达式的知识(忘了也不要紧,可以随时返回查看)。
. 表示任意一个字符,* 表示重复字符,{ } 表示限定连续字符范围,所以正则表达式也可以写成:
ifconfig eth0 |grep 'inet '| sed 's/.inet...://g' # 或者 ifconfig eth0 |grep 'inet '| sed 's/.{0,9}://'
表达式的写法并不唯一,在此也并未全部列出,大家亦可自行尝试使用其他写法,欢迎在评论区中讨论。
将 IP 后面的部分删除:
/sbin/ifconfig eth0 |grep 'inet '| sed 's/.inet...://g'| sed 's/..:.*$//g' /sbin/ifconfig eth0 |grep 'inet '| sed 's/.inet...://g'| sed 's/.{0,3}:.*$//g'
上述指令是比较复杂的正则表达式运用,熟悉正则表达式后可以明显地简化指令,简单便捷地完成文件的查询、修改等任务。
正则表达式扩展应用
使用扩展正则表达式 egrep
首先来看一条前面章节学习过的用来去除空白行和注释行的指令:
grep -v '^$' regular_express.txt |grep -v '^#'
可见,通常的 grep 指令需要使用两次管线命令。那么如果使用扩展正则表达式,则可以简化为:
egrep -v '^$|^#' regular_express.txt
利用支持扩展正则表达式的 egrep 与特殊字符 | 的组合功能来间隔两组字符串,如此一来,可以极大地化简指令。
此外,也可以使用 grep -E 来使用扩展正则表达式,不过一般更建议直接使用 egrep,grep -E 与 egrep 之间类似命令别名的关系。
扩展规则(一)
回忆一下,在非扩展正则表达式中,我们使用 * 来表示任意个重复字符(零至无穷多个):
grep -n 'goo*d' regular_express.txt
在扩展正则表达式中,则可以进一步细分为一个或一个以上和零个或一个字符:
+ 表示重复一个或一个以上的前一个字符
egrep -n 'go+d' regular_express.txt
? 表示重复零个或一个的前一个字符
egrep -n 'go?d' regular_express.txt
执行上述三条指令,比较三者的不同。
扩展规则(二)
| 表示用或(or)的方式找出数个字符串
查找 gd 或 good:
egrep -n 'gd|good' regular_express.txt
() 表示找出组字符串
查找 glad 或 good,注意到由于二者存在重复字母,所以可以将其合并:
egrep -n 'g(la|oo)d' regular_express.txt
()+ 多个重复群组判别
查找开头是 A 结尾是 C 中间有一个以上的 xyz 或 xz 字符串:
echo 'AxyzxyzxyzxyzC'|egrep 'A(xyz)+C' echo 'AxyzxyzxyzxyzC'|egrep 'A(xz)+C'
结果显示 A(xyz)+C 可以匹配,A(xz)+C 没有匹配项。