之前有写过两篇关于
sed
、
awk
的文章,但是内容太过简单了。近期打算就这方面话题写一个系列,系统介绍一些与
shell script
有关的内容。
因为即将介绍的一系列内容都将与正则表达式有关联,所以作为这个系列的开篇之作,先详细介绍一下正则表达式的使用。关于正则表达式的文章相信已经数不胜数了,我之所以再写一篇,一方面结合自己学习的心得用自己的话来组织一下,希望对刚接触正则的朋友有所帮助;另一方面也是自己再做个总结写个笔记加深理解。
进入正题吧。首先要解决的一系列问题是:正则是什么,哪些场合用到正则,正则能解决什么问题?(注:我下面要给出的一系列定义都未必是各大书籍的经典定义,而是我自己理解自己组织的语言)
正则表达式描述了特殊的字符序列,也就是,正则表达式的结果就是一系列字符,不论它有多复杂或是多简单。我们接下来要讨论的正则表达式(或称
Regular Expression
,简称
RE
)都是指
linux/unix
系统中
grep
、
ed
、
sed
工具中所使用的
RE
(使用
RE
的并非只有这些工具,例如
php
、
perl
都使用
RE
,但是他们不在我们讨论的范围之内)。为什么不提
egrep
和
awk
呢?因为他们使用的
RE
和
grep
、
sed
所使用的有些很小的区别,他们将在本文的后半部分提到。
还是举点例子吧,晦涩的文字太不直观了!我们下面的大多数例子都将以
grep
工具来讲,因为
grep
是
linux/unix
系统最常用最简单而且要使用
RE
的工具!既然要拿
grep
来举例,还是先介绍一下
grep
吧。
grep
命令的作用是在一个或多个文件中搜索特定的字符串,语法为:
grep pattern file(s)
每个文件中符合模式
pattern
的字符串所在的行都将显示在终端上。(注意,这里的
pattern
将广泛使用在
grep
、
sed
、
awk
中,事实上
RE
就是使用在
pattern
中的!)最简单的一个例子
:
grep ‘root’ /etc/passwd
上面这个
grep
命令中,
root
就是一个最简单的
RE
!整条命令的意思就是:在文件
/etc/passwd
中搜索包含字符串
root
的行,并把它(们)显示出来。(这里的单引号
’’
要讨论起来过于复杂,我们将在其他的文章中重点讨论,记得先这么用吧
grep ‘xxxx’ file
)
为什么
root
也是一个
RE
呢?别把
RE
看得过于复杂,在不使用特殊字符(在
RE
中称为元字符)的情况下,
RE
就是一个一个的字符而已!记住:
RE
都只是处理单个字符的!
root
这个
pattern
到底是怎么工作的呢?很简单,就是在每一行先找
r
字符,如果找到了,再依次找
oot
。换句话说,就是要找到
r
后面紧跟着
o
再紧跟着
o
再紧跟着
t
的,才把该行显示出来。再复杂的
RE
也都是这样工作的!那
RE
岂不是很简单?它难在哪里呢?难就难在它最强大的地方,模糊匹配,也就是下面要讲的元字符。(如果没有元字符,都像
’root’
这样,也就没必要搞什么
RE
了,
pattern
里写个单词不就得了)
重点难点的元字符来了啊!很多书和文章都会一鼓脑儿把元字符列一张表,让学习者去理解或者背下来。这样的效果是,那张表不结合实例看三遍以上是理解不了的!结合我以前学习的心得,我把元字符分成
2
类来介绍。其实元字符总共也没几个,分类是为了便于理解。
第一类:可以单独使用的元字符。这类字符有
(
下面列出来的字符都请一个一个的看,不要连起来,因为他们都是独立存在就有意义的
)
. ^ $<?XML:NAMESPACE PREFIX = O />
.
代表任意单个字符
^
作为
RE
的第一个字符,代表行的开始;在其他位置是普通字符
$
作为
RE
的最后一个字符,代表行的结束;在其他位置是普通字符
举例:
$cat file
11111.1
2222^2
3333$3
注意这是一个空行
$grep ‘.’ file
11111.1
2222^2
3333$3
为什么会显示三行呢?因为命令中的
.
是元字符,而不是普通的点。元字符
.
代表任何单个字符,所以只要有字符的行,这条
grep
命令都会把它显示出来。
$grep ‘^’ file
11111.1
2222^2
3333$3
注意这里的空行也显示了
为什么没有
^
符号的行也显示呢?因为这个
RE
中
^
是在第一个字符位置,这里的
^
代表行首,只要有行首的行都显示(任何行哪怕是空行都有行首和行尾)同样的道理
grep ‘$’ file
也会显示所有行。
$grep ‘.^’ file
2222^2
这个命令中的
^
前面有个元字符,所以这里的
^
不表示行首,而是个普通字符;
.^
表示一个任意字符后面紧跟字符
^
,这里匹配的内容就是
2^
,于是这一行被显示。
$grep ‘$.’ file
3333$3
这个命令中的
$
后面有一个元字符,所以不表示行尾,
$.
匹配的是
$3
,于是该行被显示。
$grep ‘^$’ file
这里显示了一个空行
^$
匹配行首和行尾之间没有字符的行,也即是空行了。
^$
表示空行,而
^ $
(中间有个空格哦)表示只有一个空格的行。
好了,第一类元字符介绍完了,简单吧,只有三个而已。
第二类,用来修饰其他字符(普通字符或第一类元字符)的元字符,这一类元字符要多一些,一个一个来吧。
常用的匹配单个字符的还有
[]
,
[…]
匹配括号中的字符之一。下面列举一些常见的使用方式:
[abc]
匹配单个字符
a
或
b
或
c
[123]
匹配单个字符
1
或
2
或
3
[a-z]
匹配小写字母
a-z
之一
[a-zA-Z]
匹配任意英文字母之一
[0<?XML:NAMESPACE PREFIX = ST1 />-9a-zA-Z]
匹配任意英文字母或数字之一
注意上面标红色的单个和之一了吧,不管
[]
里面多复杂,它的结果都是一个字符!
在
[]
里面的字符值得注意的有几个特例:
- ^ [ ]
(也请分开一个一个看)
-
在上面的例子已经提到了,表示范围。但是注意:如果
-
符号出现在
[]
里面的首尾位置是普通字符。
例如:
[-abc-]
匹配字符
-abc
之一
-
符号虽然出现了
2
次,这里和一个
-
是同样的意义,试想
aa
之一和
aaa
之一有区别吗?
^
符号如果出现在
[]
的起始位置表示否定,但是在其他位置是普通字符。
[^ab^c]
匹配不是
a
或
b
或
^
或
c
的任意字符
$cat file
Aaaaabc
Bbbbbbc^
cccccbc33
$grep ‘[^ab^c]’ file
cccccbc33
只有第三行的
3
满足了匹配要求,所以只显示这一行。
$grep ‘[x^]’ file
Bbbbbbc^
[x^]
匹配字符
x
或
^
如果
[]
中要包含字符
[
和
]
该怎么办呢,
[][]
应该怎么理解呢?
[[]]
又怎么理解呢?有一个原则:字符
]
和
[
放在
[]
中,只有紧跟在
[
后面的
]
和紧贴于
]
前面的
[
是普通字符。还有一个更好理解的方式,就是用反斜杠转义
[]
中的
[
和
]
,如
[\[\]],
当然这看起来同样不那么舒服。
除了
[]
之外,还有很多第二类元字符,先来整体认识一下他们吧(这次不是一个一个看了,以空格为分界来分段看吧)
* \ \? \+ \{n,m\}
*
用于修饰前导字符,表示前导字符出现任意多次
\?
用于修饰前导字符,表示前导字符出现
0
或
1
次
\+
用于修饰前导字符,表示前导字符出现
1
或多次
\{n,m\}
用于修饰前导字符,表示前导字符出现
n
至
m
次
(
n
和
m
都是整数,且
n<m
)
\
用于转义紧跟其后的单个特殊字符,使该特殊字符成为普通字符
注:以上“前导字符”表示紧贴于元字符前面的单个普通字符或第一类元字符。举例吧:
a*
匹配连续的任意(也包括
0
)个
a
.*
匹配连续的任意(也包括
0
)个任意字符,传说中的万能匹配!
a\?
匹配
0
或
1
个
a
a\+
匹配
1
或多个
a
a\{3,5\}
匹配
3
至
5
个连续的
a
\.*
匹配
0
或多个连续的
. \.
表示普通字符句点
.
注意到没有,
* \? \+ \{n,m\}
这几种元字符完成类似的功能,都是匹配连续出现的前导字符,只是出现的次数不一样罢了,不是很难吧。
\{n,m\}
还有其他几种形式:
\{n\}
连续的
n
个前导字符
\{n,\}
连续的至少
n
个前导字符
发现没有,
\?
等价于
\{0,1\} *
等价于
\{0,\} \+
等价于
\{1,\}
特别提一下,你可能会在很多地方看到
?
和
+,
而不是这里说的
\?
和
\+
。这个问题我在开篇有所提及。
grep/sed
用的是
\?
和
\+
,普通正则
RE
;
egrep/awk
用的是
?
和
+
,扩展正则
ERE
。仅这点区别而已,
RE
和
ERE
大部分是相同的。
还有一组元字符也是常用的,但是相对比较难理解,拿到这里单独说一下:
\( \)
这里的
\(
和
\)
一定是成对出现的
,
这对带反斜杠的小括号的意义是:将小括号中匹配的字符串存储到下一个寄存器中
(1-9)
。
\( \)
在
sed
的
s///
替换中经常使用,其实它并不限于应用在
sed
中,举例:
^\(.\)
行中第一个字符存到
1
号寄存器中(为什么是行中第一个字符?回上面复习一下吧
^\(.\)\1
行首两个字符,且他们相同
^\(.\).*\1$
行首尾两个字符相同
\1
的意思就是取
1
号寄存器的内容,这是固定格式
\n
(
1
≤
n
≤
9
)
$cat file
aaaaabc
bc^b
1234
gdfdd
$ grep '^\(.\)\1' file
aaaabc
$ grep '^\(.\).*\1$' file
bc^b
正则表达式理论方面的就介绍到这里了,下面再补充一些更常用也更长一点的
RE
例子。
[0-9a-z?,.;:’”]
这个表达式将匹配“任意单个字符,可以是数字、小写字母、问好、逗号、句号、分号、冒号、单引号或双引号
[0-9]\{2\}
连续的两位数字
[0-1][0-9][-/][0-3][0-9][-/][0-9]\{2\}
这个表达式能够用来表示时间格式
MM-DD-YY
或
MM/DD/YY,
方括号
[]
中的
-
放在第一个位置,确保它在
[]
中不被解释为范围,而是普通字符
-
还有一点要注意的,就是
\{2\}
仅是用来修饰前面的单个字符的,别忘了
[0-9]
也是单个字符
gep ‘<.*>’ file
将匹配所有带有
<>
标记的行
can[ no’]*t
将匹配
cant
、
can t
、
cannt
、
cannot
、
cann’t
、
cannnnnnt
等等。。。
80[234]\ ?86
将匹配
8086
、
80286
、
80386
、
80486
^$
匹配空行
^.*$
和
.*
都匹配任意行(包括空行)
[0-9][0-9]*\.\{5,\}[0-9][0-9]*
匹配“至少一位数字紧跟至少
5
个句点紧跟至少一位数字。这个正则应该分段来看:
[0-9]
是一位数字;
[0-9]*
是
0
或多位数字;
[0-9][0-9]*
就是“至少一位数字”,相当于
[0-9]\+
\.\{5,\}
中的
.
被转义了,表示普通的
.
于是
\.\{5,\}
就表示
”
至少
5
个句点
”
先举这些例子吧,更多的例子以后再更新了
转载于:https://blog.51cto.com/shitou118/210959