Linux Shell
以一串字符作为表达式向系统传达意思。元字符(Metacharacters)
是用来阐释字符表达式意义的字符,简言之,元字符就是描述字符的字符,它用于对字符表达式的内容、转换及各种操作信息进行描述。正则表达式是由一串字符和元字符构成的字符串,简称RE(Regular Expression)
。正则表达式的主要功能是文本查询和字符串操作,它可以匹配文本的一个字符或字符集合。
在Linux系统中,程序设计语言Java、Perl和Python等,Shell工具 sed、awk和grep等,以及MySQL和PostgreSQL等数据库服务器都使用了正则表达式,下图描述了正则表达式用于数据流处理的过程。实际上,正则表达式完成了数据过滤,将不满足正则表达式定义的数据拒绝掉,剩下与正则表达式匹配的数据。
正则表达式的基本元素包括普通字符和元字符,例如,a、b、1、2等字符属于普通字符,普通字符可以按照字面意思理解,如:a 只能理解为英文的小写字母a,没有其他隐藏意义。而*
、^
、[]等
元字符,Shell赋予了它们超越字面意思的意义,如:*
号符号的字面意义只是一个符号,而实际上却表示了重复前面的字符0次或多次的隐藏意义。因此,掌握正则表达式基本元素主要是对正则表达式中元字符意义的掌握。
POSIX标准将正则表达式分为两类:基本的正则表达式和扩展的正则表达式,大部分Linux应用和工具仅支持基本的正则表达式,因而,本文所诉的正则表达式基础是掌握正则表达式的关键,下图列出基本的正则表达式中元字符集合及其意义。
符号 意义
*
0 个或多个在*字符之前的那个普通字符
.
匹配任意字符
^
匹配行首,或后面字符的非
$
匹配行尾
[]
匹配字符集合
\
转义符,屏蔽一个元字符的特殊意义
\<\>
精确匹配符号
\{n\}
匹配前面字符出现 n 次
\{n,\}
匹配前面字符至少出现 n 次
\{n,m\}
匹配前面字符出现 n ~ m 次
下面逐一介绍正则表达式元字符的意义和用法,并举一些例子结合使用元字符。
1. *
符号
*
符号用于匹配前面一个普通字符的 0 次或多次重复,如:
hel*o
*
符号前面的普通字符是l,*
字符就表示匹配l字符0次或多次,如字符串helo、hello、helllllo都可以由hel*o来表示
2. .
符号
点号 .
用于匹配任意一个字符,如:
...73.
由于 .
符号只能匹配一个字符,因此,上述字符串表示前面三个字符为任意字符,第4和第5个字符是7和3,最后一个字符为任意字符,如xcb738、4J973U都能匹配上述字符串。值得注意的是 .
符号可以匹配一个空格,因此, x b738、ui 73e也能匹配上述字符串。
3. ^
符号
^
符号用于匹配行首,表示行首的字符是 ^
字符后面的那个字符,如:
^cloud
这表示匹配以cloud开头的行。结合上面介绍的 *
符号和 .
符号,再举一个例子:
^...X86*
该字符串表示行首的三个字符为任意字符(可以是空格),第 4 ~ 6 个字符为 X86,第7个字符开始可以重复匹配6,如:866X86666、8 6X86都可以匹配上述字符串。
4. $
符号
$
符号匹配行尾,$
符号放在匹配字符之后,与 ^
符号的功能和用法都相反,如:
micky$
该正则表达式表示匹配以micky结尾的所在行。一个特殊的正则表达式是匹配所有空行的表达式,为:
^$
该正则表达式既匹配行首,又匹配行尾,中间没有任何字符,因此,为空行。
如果需要匹配只包含一个字符的行,如:
^.$
5. []
符号
方括号[]
匹配字符集合,该符号支持穷举方法列出字符集合的所有元素,也支持使用 -
符号表示字符集合范围,表明字符集合范围从 -
左边字符开始,到 -
右边字符结束。如果要匹配任意一个数字,可以使用如下的两种方法,前一种穷举了阿拉伯数字,后一种用数字范围表示,显得比较简洁。
[0123456789] [0-9]
[]
也可以用作字母匹配,如:
[a-z] // 所有小写字母 [A-Z] // 所有大写字母 [b-p] // 小写字母b到p
Linux系统对小写是敏感的,并且支持字母排序,因此,Linux中有大写字母序列和小写字母序列,两者是分开的,a~z
表示所有小写字母,A~Z
表示所有大写字母,而b~p
表示从b到p之间的所有小写字母。
我们知道,^
符号表示匹配行首,但是,^
符号放到[]
符号中就不再表示匹配行首了,而是表示取反符号。
[^b-d]
以上正则表达式匹配不在b~d范围之内的所有字符,此时,符号^
不再表示匹配行首,而是取反符号,不在b~d
范围内的字符实际上涵盖了除了小写字母b、c和d之外的所有字符(包括其他字母、数字、空格等)。再举一个[]
符号和 *
符号结合的例子:
[A-Za-z] [A-Za-z]*
以上正则表达式表示任意一个字母开头,再以任意字母进行 0
次或任意次重复,实际上,这个正则表达式可以匹配任意英文单词。
6. \
符号
\
符号是转义符,用于屏蔽一个元字符的特殊意义,即以字面含义来解释 \
符号后面的元字符,如:
\.
反斜杠后面的字符 .
是元字符,经过转义后 .
不再表示任意一个字符,而是一个普通字符点号 .
转义符 \
是引用符的一种。
7. \<\>
符号
\<\>
符号是精确匹配符号,该符号利用 \
符号屏蔽 <>
符号,如:
\<the\>
该正则表达式精确匹配 the
这个单词,而不匹配包含 the
字符的单词,如 them
、there
、another
等。
8. \{\}
系列符号
\{\}
系列符号与 *
符号类似,都表示前一个字符的重复。但是,*
符号表示重复 0
次或任意次,而 \{\}
系列符号可以指定重复次数,\{\}
系列符号包括三种形式。
- \{n\} 匹配前面字符出现 n 次
- \{n,\} 匹配前面字符至少出现 n 次
- \{n,m\} 匹配前面字符出现 n ~ m 次
JO\{3\}B 重复字符 O 3 次 JO\{3,\}B 重复字符 O 至少 3 次 JO\{3,6\}B 重复字符 O 3 ~ 6 次 JO\{3\}B 表示重复字符 O 3次,匹配值为:JOOOB JO\{3,\}B 表示重复字符 O 至少 3次,JOOOB、JOOOOB、JOOOOOB等字符都可由该正则表达式来匹配 JO\{3,6\}B 表示重复字符 O 至少 3 次,最多 6 次,JOOOB,JOOOOOOB等字符串都满足,但是JOOB、JOOOOOOOO等字符串就不满足。 [a-z] \{5\}
改正则表达式表示精确匹配 5
个小写英文字母,比如 hello、house 等。
正则表达式的扩展
除了最基本的正则表达式的元字符外,awk和Perl等Linux工具还支持正则表达式扩展出来的一些元字符。
符号 意义
?
匹配 0 个或 1 个在其之前的那个普通字符
+
匹配 1 个或多个在其之前的那个普通字符
()
表示一个字符集合或用在expr中
|
表示“或”,匹配一组可选的字符
下面详细介绍扩展的正则表达式元字符及其用法
1. ?
符号
匹配 ?
符号之前的那个字符 0 次或 1 次,如:
JO?B
该表达式表示匹配O字符0次或1次,即匹配JOB或JOOB。需要注意的是,?
字符最多可以匹配1个字符。
2. +
符号
与 *
符号类似,都是匹配其前面的那个字符多次,但是 *
字符可以匹配 0 次,而 +
符号可以匹配 1 次,如:
S+EU
该正则表达式表示匹配S 1次或任意次,SSEU、SSSSEU 等字符串都可由该表达式进行匹配,而SEU却不能由S+EU来匹配。
3. ()
符号和 |
符号
()
符号通常与 |
符号结合使用,表示一组可选字符的集合,如:
re(a|e|o)d
该正则表达式中的(a|e|o)
表示在字符a、e和 o 中选择任意一个字符,即 read、reed、reod 都可由该表达式进行匹配。
事实上 ()
符号很少被使用到,因为 []
符号完全能够替代 ()
符号表示一组可选字符的集合,re(a|e|o)d
等价于:
re[aeo]d
|
符号也可以表示多个正则表达式的 或 关系,基本格式为:
RE1 | RE2 | RE3
上述格式中,RE1、RE2、RE3表示正则表达式。
|
符号在扩展的正则表达式中表示 或 遗憾的是 |
符号的这种用法却很少被人记住 |
符号最著名的是其管道符用法。