1. 什么是正则表达式

简单的说,正则表达式是一种用于识别文本模式的符号表示法。grep的基本功能是在文本文件中搜索与指定的正则表达式匹配的文本。

1.1 元字符

除了普通字符,正则表达式还包括元字符,用于指定更复杂的匹配。正则表达式的元字符包括,其他所有字符均被视为普通字符。少数情况下,反斜线可用于创建元序列,还能转义元字符,使其称为普通字符。


^ $ . [ ] { } - ? * + ( ) | \


很多正则表达式元字符对Shell扩展具有特殊含义,当包含元字符的正则表达式出现在命令行上时,一定要记得将其放入单引号中,避免Shell去扩展这些字符。

BRE(Basic Regular Expression)基本型正则表达式,识别下列元字符


^ $ . [ ] *


ERE(Extended Regular Expression)扩展型正则表达式,识别下列元字符


{ } ? + ( ) |


但是,如果使用反斜杠将(、)、{、}转义的话,BRE将其视为元字符;而ERE会将转义后的这些字符视为文字字符。

1.2 匹配行首和行尾

使用定位符控制正则表达式在哪个位置上查找匹配项

  • 行首搜索,使用脱字符(^) 示例:^cat
  • 行尾搜索,使用美元符号($) 示例:dog$
  • 查找行中唯一的词语,同时使用行首和行尾定位符 示例:^cat$
  • ^$,表示行首和行尾之间什么都没有,匹配空行。

1.3 向正则表达式添加通配符

  • 正则表达式使用(.)来匹配除换行符之外的任何单个字符
  • 匹配特定字符,将表达式更改为c[aou]t,匹配以c开头,后面跟着a,o或u,然后是t。使用方括号表达式匹配指定字符集合的单个字符。集合中可以包含任意数量的字符,其中出现的元字符会丢失其特殊含义。但是,有两种特殊情况:脱字符用于表示否定;连字符表示字符范围。

示例:

#1. 方括号表达式中的首个字符是脱字符,剩下的字符则被视为不该在指定字符位置上出现的字符集合。排除型字符集合仍需要指定位置上有一个字符存在,只不过这个字符不能是集合中的字符。
[root@ansible tmp]# grep -h '[^bg]'zip dirlist*.txt
bunzip2
funzip
gpg-zip
gunzip
mzip
unzip
#2. 匹配以字母或数字开头的所有文件名
[root@ansible tmp]# grep -h '^[A-Za-z0-9]'zip dirlist*.txt
bzip2
bzip2recover
gzip
mzip
bzip2
bzip2recover
gzip
mzip

1.4 多选结构

  1. 单选
[root@ansible tmp]# echo "AAA" | grep 'AAA'
AAA
  1. 二选一
[root@ansible tmp]# echo "BBB" | grep -E 'AAA|BBB'
BBB
[root@ansible tmp]# echo "BBB" | egrep 'AAA|BBB'
BBB

  1. 多选一
[root@ansible tmp]# echo "CCC" | egrep 'AAA|BBB|CCC'
CCC
[root@ansible tmp]# echo "CCC" | grep -E 'AAA|BBB|CCC'
CCC

4.多选结构与其他正则表达式的组合,匹配文件列表中以bz、gz或zip开头的文件名

[root@ansible tmp]# grep -Eh '^(bz|gz|zip)' dirlist*.txt

5.上例中去除括号,匹配以bz开头、或者包含gz,或者包含zip的文件名

[root@ansible tmp]# grep -Eh '^bz|gz|zip' dirlist*.txt

1.5 向正则表达式添加倍数

倍数是常与通配符一起使用,倍数应用到正则表达式中的前一位字符。常用的倍数:

  1. 星号(*)表示匹配前一表达式的零项或多项。可以在表达式中使用*,而不仅限于字符。示例:c[aou]*t。正则表达式c.*t将匹配cat、coat、culvert乃至ct(c和t之间没有字符)。任何以c开头,后面跟着零个或多个字符,最后以t结尾的数据。
    #判断字符串是否是一句话,该字符串以大写开头,然后是任意多个大/小写字母和空格符
    [root@ansible tmp]# echo "This is a boy." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
    This is a boy.
    
  2. {}表示模式中前面字符的期望个数,'c.{2}t’是使用显示倍数的一个示例。该正则表达式将匹配以c开头,后面跟着任意两个字符,最后以t结尾的任何词语。
    #匹配两种类型的电话号码(nnn) nnn-nnnn和nnn nnn-nnnn
    [root@ansible tmp]# grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$' test
    
  3. 问号(?)表示模式中匹配0次或1次
    #匹配两种类型的电话号码(nnn) nnn-nnnn和nnn nnn-nnnn
    grep  '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$' test
    
  4. 加号(+)表示模式中匹配1次或多次
    #匹配单个空格符分割的一个或多个字母
    [root@ansible tmp]# grep -E '^([[:alpha:]]+ ?)+$' test1
    this what
    a b c
    

由于正则表达式常含有shell元字符(如$、*和{}),建议练习使用单引号来括起正则表达式。这样可确保字符由命令解释,而不是由shell解释。

正则表达式

选项描述
.句点(.)匹配任何单个字符
前面的项目是可选的,且最多匹配一次
*前面的项目将匹配零次或多次
+前面的项目将匹配一次或多次
{n}前面的项目恰好匹配n次
{n,}前面的项目恰好匹配n次或更多次
{,m}前面的项目最多匹配m次。
{n,m}前面的项目至少匹配n次,但不超过m次。
[:almum:]字母数字字符,等同于[0-9A-Za-z]
[:alpha:]字母字符,等同于[A-Za-z]
[:blank:]空白字符:空格和制表符
[:cntrl:]控制字符
[:digit:]数字:0-9
[:graph:]图形字符
[:lower:]小写字母
[:print:]可打印字符:[:almum:]、[:punct:]和空格
[:punct:]标点符号
[:space:]空格字符;制表符、换行符、垂直制表符、换页符、回车符和空格
[:upper:]大写字母
[:xdigit:]十六进制数字
\b匹配词语两侧的空字符串
\B匹配词语中间的空字符串
<匹配词语开头的空字符串
>匹配词语末尾的空字符串
\w匹配词语组分
\W匹配非词语组分
\s匹配空格
\S匹配非空格

1.6 grep选项

常用grep选项表

选项功能
-i不区分大小写
-v反向匹配,仅显示不包含正则表达式匹配项的行
-r将递归地将匹配正则表达式的数据搜索应用到一组文件或目录
-A NUMBER显示正则表达式匹配项之后的行数
-B NUMBER显示正则表达式匹配项之前的行数
-e使用-e选项,可以提供多个正则表达式,并将与逻辑或一起使用
-c输出匹配数量
-l输出包含匹配项的文件名,不再输出文本行。
-L和-l选项类似,但是只输出不包含匹配项的文件名
-n在包含匹配项的文本行前加上行号
-h在多文件搜索中禁止输出文件名

grep还有很多其他选项,使用man page可以对它们进行研究。

1.7 使用find查找路径名

通过正则表达式搜索,找出包含内嵌空格符和其他潜在不规范字符的路径名:

[root@ansible tmp]# find . -regex '.*[^-_./0-9a-zA-Z].*'
./etc/systemd/system/getty.target.wants/getty@tty1.service
./etc/systemd/system/dev-virtio\x2dports-org.qemu.guest_agent.0.device.wants

1.8 使用locate搜索文件

locate程序既支持BRE(–regexp选项),也支持ERE(–regex选项)

[root@ansible tmp]# locate --regex 'bin/(bz|gz|zip)'

1.9 Less和Vim中使用正则表达式搜索文本

  • Less支持ERE和BRE
[root@ansible tmp]# less phonelist.txt
(538) 794-599
(455) 199-8136
(853) 247-1873
(261) 191-8873
(296) 691-0723
(158) 594-7899
(292) 892-0199
(518) 473-8491
(948) 389-0795
(846) 249-8228
(931) 979-6425
(481) 802-3580
(378) 694-1509
(333) 991-736
#执行less命令后,先输入斜杠,然后输入正则表达式进行匹配
/^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$
  • Vim只支持BRE,因此上述的正则表达式得改写成这样
/([0-9]\{3\}) [0-9]\{3\}-[0-9]\{4\}$

更多推荐

Linux正则表达式