欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

shell脚本学习9-正则表达式

程序员文章站 2022-07-10 09:26:47
...

shell脚本经常要处理大量数据如日志等,有些内容需要用到正则表达式,正如之前的sed和gawk,里面经常使用正则表达式。正则表达式要通过正则表达式引擎实现,负责对表达式的模式进行解释。当前有两种引擎,分别是基础正则表达式引擎(BRE)和扩展正则表达式引擎(ERE)。

  1. BRE模式
    1.1 纯文本正则表达式匹配
    之前的sed和gawk中已经用到过纯文本的正则表达式,纯文本正则表达式中是没有特殊字符的,比如输入:
echo 'wu lin wai zhuan'|sed -n '/wai/p'

运行后结果为:

wu lin wai zhuan

再输入:

echo 'wu lin wai zhuan'|gawk '/lin/{print $0}'

运行后结果为:

wu lin wai zhuan

如果字符串本身中有空格的话,同样可以添加空格作为字符串的一部分,输入:

echo 'wu lin wai zhuan'|sed -n '/ai zh/p'

运行后结果为:

wu lin wai zhuan

1.2 特殊字符构造的正则表达式
有一些字符有特别的含义,在纯文本中是不能直接使用的,如果想要在纯文本中使用的话必须在这些特殊字符前面加上转义符号\进行转义,特殊符号包含:

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

比如输入:

echo "\ is character"|sed -n '/\/p'

运行结果为:

sed: -e 表达式 #1, 字符 4: 未终止的地址正则表达式

然后加上转义符号进行转义:

echo "\ is character"|sed -n '/\\/p'

运行结果为:

\ is character

注意:虽然正斜线/不是正则表达式的特殊符号,但是如果出现在sed和gawk中,也要进行转义,比如输入:

echo "3 / 2 = 1" |sed -n '///p'

运行后报错:

sed: -e 表达式 #1, 字符 3: 未知的命令:“/”

进行转义:

echo "3 / 2 = 1" |sed -n '/\//p'

结果为:

3 / 2 = 1

1.2.1 锚字符
锚字符用于匹配一个模式出现行首或者行尾,也就是说当模式出现在行首或者行尾的时候才能匹配成功。
1.2.1.1 脱字符匹配行首
脱字符(^)匹配对应的模式是否出现在行首,如果不是在行首,即使有对应的字符串也不会匹配:
比如输入:

echo "wu lin wai zhuan"|sed -n '/^wu/p'

运行后结果为:

wu lin wai zhuan

再输入:

echo "wu lin wai zhuan"|sed -n '/^lin/p'

运行后结果为空。
注意:如果把脱字符放到其他位置,也就是非开头的位置,那么他就是一个普通字符,而且也不用转义符号进行转义,比如说输入:

echo "The character ^ is normal" |sed -n '/ter ^ is/p'

运行后结果为:

The character ^ is normal

当然如果加了转义符号也不会出错的,比如输入:

echo "The character ^ is normal" |sed -n '/ter \^ is/p'

其结果也是:

The character ^ is normal

1.2.1.2 美元符号匹配行尾
同理,用于以某个字符串结尾的模式可以使用美元符号$去匹配。比如输入:

echo "wu lin wai zhuan"|sed -n '/zhuan$/p'

运行后结果为:

wu lin wai zhuan

再输入:

echo "wu lin wai zhuan"|sed -n '/lin$/p'

运行后结果为空。

1.2.1.3 锚点组合
把脱字符和美元符号同时使用的时候可以只筛选出该行内容为指定模式的行,比如有一个文件data,内容为:

The wu lin wai zhuan is good
wu lin wai zhuan is good

The wu lin wai zhuan
wu lin wai zhuan

输入:

sed -n '/^wu lin wai zhuan$/p' data

运行后结果为:

wu lin wai zhuan

这里只把以该字符串开头并结果的行打印出来了。
有一个经常会用的技巧,就是空行的正则表达式,^$,比如上面的data文件第三行是一个空行

The wu lin wai zhuan is good
wu lin wai zhuan is good

The wu lin wai zhuan
wu lin wai zhuan

输入:

sed '/^$/d' data

运行后结果为:

The wu lin wai zhuan is good
wu lin wai zhuan is good
The wu lin wai zhuan
wu lin wai zhuan

该命令删除了第三行中的空行。

1.2.2 点号
点号(.)用于匹配出换行符之外的任何单个字符,必须匹配一个字符。比如文件data2的内容为:

wu lin wai zhuan
wu l in wai zhuan
lin wai zhuan
wulinwaizhuan

输入:

wu lin wai zhuan
wulinwaizhuan

第二行没有匹配是因为没有lin,第四行没有匹配是因为没有与点号匹配的字符,因为点号至少需要一个字符与其匹配。

1.2.3 方括号
方括号在正则表达式中应用广泛,用于限定所有的可匹配字符,方括号在正则表达式中有以下四种常用用法。
1.2.3.1 方括号中列出所有的匹配字符,然后选一个
输入:

echo "wu lin wai zhuan"|sed -n '/[uvwxyz]ai/p'

运行后结果为:

wu lin wai zhuan

再输入:

echo "wu lin wai zhuan"|sed -n '/[uvxyz]ai/p'

运行后结果为空。

注意:每一对方括号必须要匹配一个字符,如果有多个不确定字符的话那就用多个方括号,比如下面这个输入:

echo "zhao ben shan"|sed -n '/[bB][eE][nN]/p'

运行后结果为:

zhao ben shan

1.2.3.2 方括号中加入^,不匹配括号中的字符
方括号中第一个字符如果是脱字符^的话,那么就匹配非括号中的字符,修改一下上面的data2文件,内容为:

wu lin wai zhuan
wu l in wai zhuan
lin wai zhuan
inwaizhuan

输入:

sed -n '/[^lL]in/p' data2

运行后结果为:

wu l in wai zhuan

这说明空格字符被匹配上了。同时也要注意,虽然使用了脱字符,但是方括号规定了必须要匹配一个字符,所有最后一行没有匹配中。

1.2.3.3 方括号中使用区间,而不是一个个列出来所有的字符
如果在方括号中要列出来的字符比较多,可以通过一种简单的方法,用破折号把范围的起始字符和终止字符连起来,比如数字[0123456789]可以写成[0-9],比如有一个文件:

12345
1234
123

输入:

sed -n '/^[0-9][0-9][0-9]$/p' data3

运行后结果为:

123

这里把长度为3的数字过滤出来。
可以把多个范围写在一个方括号,比如输入:

echo "wu lin wai zhuan"|sed -n '/[a-cu-z]u/p'

运行后结果为:

wu lin wai zhuan

可以看出,ac和uz范围的字符都能匹配。

1.2.3.4 自带的特殊字符正则表达式
正则表达式引擎中自带了一些特殊字符,这些字符要用到双方括号中去才能生效:
1) [[:alpha:]] 匹配任何字母,无论大小写
2) [[:alnum:]] 匹配任何字母,无论大小写,还匹配数字0~9
3) [[:blank:]] 匹配空格和制表符
4) [[:digit:]] 匹配数字0~9
5) [[:upper:]] 匹配大写字母
6) [[:lower:]] 匹配小写字母
7) [[:punct:]] 匹配标点符号
8) [[:print:]] 匹配可打印字符
比如输入:

echo "123" |sed -n '/[[:digit:]]3/p'

运行后结果为:

123

输入:

echo "123" |sed -n '/[[:alpha:]]4/p'

运行后结果为空
输入:

echo "test, pass" |sed -n '/[[:punct:]]/p'

结果为:

test, pass

1.3 星号
之前认识到点号是匹配一个字符,星号是匹配0次或者多次,表示星号前面的这个字符可以出现0次或者多次。比如有一个文本data4的内容为:

abc
abbc
ac
a

输入

sed -n '/ab*c/p' data4

运行后结果为:

abc
abbc
ac

注意:经常把点号和星号在一块使用,能表示任何数量的任意字符,通常情况下,你知道一句话的两个单词但是不知道两个单词中间是否有其他字符的时候可以这么用,比如输入:

echo "wu lin wai zhuan"|sed -n '/wu.*wai/p'

运行后结果为:

wu lin wai zhuan

当然,星号也能与方括号联合使用,比如输入:

echo "abbbc"|sed -n '/a[a-z]*c/p'

运行结果为:

abbbc
  1. ERE模式
    ERE模式比BRE能支持更多的操作,当前sed不支持ERE,gawk支持ERE。
    2.1 问号
    之前介绍了点号匹配一次,星号匹配0次或多次,而问号是匹配0次或1次。
    比如文件data4的内容为:
abc
abbc
ac
a

输入:

gawk '/ab?c/{print $0}' data4

运行结果为:

abc
ac

可以看出abbc没有匹配上,同样,这里也可以使用BRE中的一些规则,比如使用方括号指定范围,输入:

gawk '/a[a-c]?c/{print $0}' data4

运行结果为:

abc
ac

2.2 加号
问号匹配0次或1次,而加号匹配1次或多次。比如文本data4的内容为:

abc
abbc
ac
a

输入:

gawk '/ab+c/{print $0}' data4

运行后结果为:

abc
abbc

2.3 花括号
花括号用于限定字符出现的个数,有两种用法:
{m}表示前面的字符出现m次;
{m,n}表示前面的字符出现次数大于m次小于等于n次
比如文件data6的内容为:

ac
abc
abbc
abbbc

输入:

gawk '/ab{1,2}c/{print $0}' data6

运行后结果为

abc
abbc

2.4 OR操作
使用单竖线(管道符号),可以实现或的操作,也就是竖线左右两侧只要有一个匹配成功则输出,比如输入:

echo "zhao ben shan"|gawk '/b[a-z]+n|dan/{print $0}'

运行结果为:

zhao ben shan

注意上面的左右两侧的模式也是可以使用正则表达式。

2.5 小括号变零为整
正则表达式中可以使用小括号包起来一些字符或者其他正则表达式,小括号的内容可以看成一个整体。比如文本data7的内容为:

January
Jan

输入

 gawk '/Jan(uary)?/{print $0}' data7

运行结果为:

January
Jan

这里表示uary这个整体可能出现0次或者1次。
还有一种非常常用的用法,把小括号和管道符号联合使用,用于匹配模式的组合,比如有文件data8内容为:

abc
dbc
abf
dbf
def

输入:

gawk '/(a|d)b(c|f)/{print $0}' data8

运行后结果为:

abc
dbc
abf
dbf

小括号里面的字符随意选择一个即可匹配成功。

  1. 总结与展望
    3.1 总结
    a) 正则表达式引擎分两种,基础正则表达式引擎(BRE)和扩展正则表达式引擎(ERE);
    b) 用纯文本构造正则表达式;
    c) 锚字符在正则表达式中的使用,锚字符和美元字符的区别,以及二者的组合,包括空行怎么筛选;
    d) 点号匹配一个任意字符;
    e) 方括号中列出所有的匹配字符;方括号中加入^,不匹配括号中的字符;方括号中使用区间;方括号中使用自带的表达式
    f) 星号匹配0次或者多次;
    g) 问号匹配0次或1次;
    h)加号匹配1次或多次;
    i) 花括号用于限定字符出现的个数,两种用法{m}和{m,n}的区别;
    j) 单竖线使用OR操作;
    k)小括号变零为整;
    3.2 展望
    当前已经系统学习了shell脚本的所有知识,之后将会在实践中使用shell脚本来解决实际中的一些问题。