本篇博客内容:
一:正则和通配符的区别
二:正则表达式运用场景
三:正则表达式的相关说明
四:正则表达式的介绍(重点)
4.1 基本正则表达式
4.2 扩展正则表达式
4.3 POSIX字符集
正文:
1 正则表达式和Bash Shell通配符区别
在前一节认识了通配符后,就能发现“通配符”和“正则表达式”还是挺像的。但是,有一点必须要知道:Bash Shell中的通配符和正则表达式是完全不同的两个东西,只是在某些符号和某些释义上有交叉而已。
Bash Shell本身是不支持正则表达式的,它的语法也解释不了正则表达式,同时Bash Shell中的通配符不依据正则表达式标准。
问1:既然Bash Shell中不支持正则表达式,为什么输入命令时,会有正则表达式的出现?
答:虽然Bash Shell命令行解释器本身解释不了正则表达式,但是在bash shell的工具中,有的是支持正则表达式标准的,比如,vi、grep、sed、awk等工具。这些正则表达式最终不是由Bash命令行解释器进行解释的,而是在某一个工具中进行解释。
需要明白的是,支持正则表达式的不是bash shell解释器本身,而是bash shell调用的其中的某些工具。
问2:既然在Bash shell中既可以输入通配符,又可以输入正则表达式,那么一般是按照哪种来解释的?
答:一条命令输入后,肯定是要先经过shell解析(解析过程,参考:点击打开链接)。
比如命令:grep --color -n "[a-zA-Z]*" fil*
会先对“fil* ”进行文件名匹配,而这个*就是由shell解析的,所以是被理解为通配符。
如果只有一个file是匹配的;那么经过shell解析后的命令形式就是:
grep --color -n [a-zA-Z]* file
然后就是执行grep命令,[a-zA-Z]*是提交给grep解析,这就是为什么在它两边需要加双引号的原因。是为了防止shell对该式进行错误的通配符式的文件名匹配。
所以,如果是正则表达式,确定是要提交给具体命令进行解析,而不是通过shell进行通配符匹配的,要加上双引号或者单引号。当然,单引号是最保险的。
至于shell呼叫的工具中,哪些支持正则表达式,可以查看下面的表2.1
问3:Bash Shell和它的工具(或称命令)之间又有什么联系和区别呢?
这个可以参考:点击打开链接 中的第一条:shell和命令之间有什么区别。
2 各环境对正则表达式的支持
由于正则表达式的处理对象是字符串,即文本。其主要体现在于对文本的:验证、查找、替换。在Linux系统中,程序设计语言Java、Perl和Python等;shell工具sed、awk、grep等;数据库MySQL、PostgreSQL等都采用了正则表达式。
另一方面,虽然正则表达式最开始是从UNIX系统中的某些工具开始使用,并逐渐流行开来的。但是现在正则表达式的使用范围比你想象的要广泛,很多windows下的编程软件都开始支持正则表达式,并且日常操作中,比如Notepad++、WPS、Word中的文本搜索,百度、Google中的搜索也都会用到正则表达式。
针对shell脚本而言,熟练使用正则表达式,对于掌握LInux三剑客:grep、sed、awk和Linux下强大的文本编辑器:vi而言,是非常有用的。
表2.1 shell中编辑工具对正则表达式的支持 | ||||||||||
工具 | 基本正则表达式 | 扩展正则表达式 | ||||||||
grep | √ | |||||||||
egrep | √ | √ | ||||||||
vi | √ | |||||||||
sed | √ | |||||||||
awk | √ | √ |
表2.2 各环境对正则表达式详细支持情况 | ||||||||||
命令或 环境 | . | [ ] | ^ | $ | \ ( \) | \{ \} | ? | + | | | ( ) |
vi | ✔ | ✔ | ✔ | ✔ | ✔ | |||||
awk | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ||
sed | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ||||
ex | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ||||
grep | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ||||
egrep | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
fgrep | ✔ | ✔ | ✔ | ✔ | ✔ | |||||
perl | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
Visual C++ | ✔ | ✔ | ✔ | ✔ | ✔ | |||||
Tcl 解释器 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
该表来自《UNIX技术手册》(第4版)—Arnold Robbins著 O'Reilly Taiwan公司 译 东南大学出版社
3 正则表达式相关说明
在UNIX/Linux系统中由POSIX标准来提供对正则表达式的支持。
POSIX标准将正则表达式分为两类:
1、基本的正则表达式
2、扩展的正则表达式。
而大部分Linux应用和工具仅支持基本的正则表达式。
问1:什么是POSIX标准?
POSIX标准是为UNIX和类UNIX系统,如Linux制定的一套可移植操作系统接口。所有新发布的UNIX/Linux系统,要按照该标准来设计自己新的/改进的系统。
问2:为什么要制定这套标准
由于最开始UNIX系统的发展,出现了各大厂商发布的UNIX上的代码不兼容的情况。为了增强源码在各UNIX/Linux系统上的可移植性,由IEEE制定了该标准。该标准的目的就是为了提升应用程序在各种UNIX系统环境之间的可移植性,以实现UNIX/Linux操作系统的标准化。
由于有利于厂商的利益,厂商按照这种标准来制定系统也更容易被人们接受,所以各大厂商也纷纷采用这种标准。
以上对POSIX标准的说明,主要参考:
[1] W.Richard Stevens,Stephen A.Rago. UNIX环境高级编程[M].戚正伟,张亚英,尤晋元译.第3版.北京:人民邮电出版社,2014.20~22
问3:正则表达式规范
虽然其他的组织,如windows,或语言,如PHP、Perl,有自己对正则表达式的支持和相应扩展,但是在UNIX/Linux的工具中基本就是POSIX标准制定了的对正则表达式的支持。
不同标准对正则表达式的支持可能存在差异,但大体相同。
4 POSIX标准下的正则表达式及其扩展
4.1 基本正则表达式
表4.1 基本的正则表达式元字符集合及其含义 | ||
编号 | 符号 | 意义 |
1 | * | 0个或多个在*字符之前出现的那个字符 |
2 | . | 匹配任意字符 |
3 | ^ | 匹配行首,或后面字符的非 |
4 | $ | 匹配行尾 |
5 | [ ] | 匹配字符集合 |
6 | \ | 转义符,屏蔽一个元字符的特殊意义 |
7 | \< \> | 精确匹配行号 |
8 | \{n\} | 匹配前面字符出现n次 |
9 | \{n,\} | 匹配前面字符至少出现n次 |
10 | \{n,m\} | 匹配前面字符出现n~m次 |
下面对这10种正则表达式元字符一一举例说明:
⑴、“*”符号
含义:在*之前出现的一个字符,可以出现0次或多次
如:grep --color -n 'hel*o' filename
则元字符*,限定的是字符l,重复零次或任意多次,如heo、helo、hello、helllo……
(注意对heo的匹配,因为符号“*”限定可以出现0次)
要注意一下下面这两个的区别:
[a-z]*:匹配的是任意字符 ,[a-z][a-z]*:匹配的是以任意小写字母开头的字符
⑵、“.”符号
含义:匹配任意一个字符
⑶、“^”符号
含义:匹配行首,或者是后面字符的非
释义:
① 匹配行首
一个句子有行首、行中、行尾。加了^符号,则只对首行进行字符串匹配。
对比举例:“..cloud”表示匹配前面两个字符是任意字符,后面是cloud的字符。但是这样检索,检索的是整个文本,每行的每个字符(包含行首、行中和行尾)。
加“^”后进行限定:“^..cloud”,则仅会在文本的各行行首进行检索要匹配的字符,而不是整个文本的内容了。
② 后面字符的非
当表示后面字符的非,这种含义时,是和编号5,符号“[]”这种元字符结合使用的时候才显现这种含义。
⑷、“$”符号
含义:匹配行尾
这个就不解释了,和编号3、符号“^”是相同的解释。区别就是一个行首,一个行尾;一个在前,一个在后。
用法举例:chenhaojie$
和匹配行首的:^chenhaojie,一个在头,一个在尾。
常用用法:
① 匹配空行:^$
② 匹配只有一个字符的行:^.$
⑸、“[ ]”符号
含义:匹配[ ]符号中列举的任意一个字符
用法:[ ]符号用有三种书写字符合集的方式:
① 穷举
② - :范围
③ ^ :取反
举例:[a-z]:匹配所有小写字母中的任意一个
[a-zA-Z]:匹配任意一个英文字母
[a-zA-Z][a-zA-Z]*:匹配任意英文单词
解释:为什么[a-zA-Z][a-zA-Z]* 匹配的是任意一个英文单词
“*”表示匹配前面字符零次或多次。而这里“*”前面的字符不是一个字符,而是一个字符集。相当于就是对这个字符集中的任意一个进行零次或多次匹配。
⑹、“\”符号
含义:屏蔽一个元字符的特殊意义
比如:\. 屏蔽“.”符号的任意匹配
⑺、“\<\>”符号
含义:精确匹配
啥叫精确匹配字符串。
比如:\<the\>
匹配到的就是单词the,而不是The,或者包含the的they……等等。
⑻、“\{n\}”、“\{n,\}”、“\{n,m\}”
这三种都是“\{\}”系列,和前面编号1的符号“*”很类似。
含义:
\{n\}:在该式前面出现的那个字符,再出现n-1次
\{n,\}:在该式前面出现的那个字符,再次出现至少n-1次
\{n,m\}:在该式前面出现的那个字符,再次出现n-1~m-1次
举例:
chen\{3\}hj:就是要匹配chennnhj
和“*”一样,该式可以和编号5的符号“[]”组合得到一些强大的用法:
比如:[a-z]\{5\}
表示匹配五个连续的小写字母。
4.2 扩展的正则表达式
先给出扩展正则表达式的表格:
表4.2 扩展的正则表达式元字符 | ||
编号 | 符号 | 含义 |
1 | ? | 匹配0个或1个在?之前出现的字符 |
2 | + | 匹配1个或多个在+之前出现的字符 |
3 | ( ) | 表示一个字符集合 |
4 | | | 表示或,用以表示一组可选的字符 |
5 | {n} | 和基本正则表达式编号为8、9、10的符号一样。 |
首先说明:扩展的正则表达式,并不是所有支持基本正则表达式的工具都可以用。用之前可以查看一下表2.1。
详细说明:
1、“?”符号
含义:至多匹配1个“?”前面出现的那个字符。即,匹配出现在?符号前面的那个字符,0次或1次
举例:JO?B
匹配到的字符串:JOB、JOOB (就两个)
2、“+”符号
和基本正则表达式编号1的“*”符号很像。它们唯一的区别就是:“*”符号可以匹配0次,而“+”符号至少匹配一次。
如:grep --color -n 'JO+B' filename 与 grep --color -n 'JO*B' filename
由于“+”至少要匹配一次出现在“+”前面的那个字符,所以O至少要匹配一次,从JOOB开始。
这两条命令的区别就是对 JB 与 JOB的匹配,“+”匹配不出JB和JOB。而“*”可以匹配到JB和JOB.
3、“( )”符号
字符集合。这就和基本正则表达式中编号5的“[ ]”符号很像。
而事实上,“( )”大多数情况下也确实是被“[ ]”所替代,很少被使用。
至于“( )”的用法,很多时候和符号4的“|”结合使用:
比如:(a|b|c)
或者:gawk '/^(no | so)/' file
表示匹配文件file中,以模式no或so开头的行
4.3 POSIX正则表达式字符集
1 首先,给出所有POSIX字符集,
表4.3 POSIX正则表达式字符集 | |||||
编号 | 字符集 | 含义 | 编号 | 字符集 | 含义 |
1 | [:alpha:] | 字母字符 | 7 | [:graph:] | 非空格字符 |
2 | [:alnum:] | 字母与数字字符 | 8 | [:print:] | 任何可以显示的字符 |
3 | [:cntrl:] | 控制字符 | 9 | [:space:] | 任何产生空白的字符 |
4 | [:digit:] | 数字字符 | 10 | [:blank:] | 空格与Tab键 |
5 | [:xdigit:] | 十六进制数字字符 | 11 | [:lower:] | 小写字符 |
6 | [:punct:] | 标点符号 | 12 | [:upper:] | 大写字符 |
2 使用说明:
① POSIX字符集可以通过方括号“[ ]”来引用。以编号1的字符集来说明,对它进行引用后,即为:[[:alpha:]]。
② POSIX字符集属于POSIX标准下的基本正则表达式,可以在表2.1中给出的能够使用基本正则表达式的几个工具中使用。
3 说明:
从上面的“使用说明”第一条可以知道,POSIX字符集是通过方括号引用的。方括号[ ]是用于字符的集合,但是匹配的是单个字符。
POSIX字符集,相当于是把原本放在方括号“[]”中的具有一类特征的字符做了集合,省去了手动输入的麻烦。
4 使用举例:
① 比如,替换文本中所有以小写字母组成的字符串,用数字1替换
命令:sed -n “s/[[:lower:]][[:lower:]]*/1/p” file
说明:其中的[[:lower:]][[:lower:]]*,和[a-z][a-z]*的含义是完全相等的。均表示以连续的小写字母组成的字符串。
② 再比如,查找文本中所有以字母组成的字符串。
命令:grep --color “[[:alpha:]][[:alpha:]]*” file
说明:这里的[[:alpha:]][[:alpha:]]* 与 [a-zA-Z][a-zA-Z]*含义是一样的。
——以上内容基于《Linux运维之道》 丁明一 编著
参考:
[1] gexiaobaohelloworld. Linux-正则表达式. https://blog.csdn.net/gexiaobaohelloworld/article/details/9147365#t0, 2018-5-30
[2] renwotao2009. Linux中的正则表达式. https://blog.csdn.net/renwotao2009/article/details/50937038, 2018-5-30
[3] hjlin. linux中awk,sed,grep等命令使用区别. http://blog.chinaunix.net/uid-9078996-id-2010308.html,2018-6-17