使用正则表达式最大的问题在于有不止一种类型的正则表达式。linux中的不同应用程序可能会用不同类型的正则表达式。正则表达式是通过正则表达式引擎(regular expresion engine)实现的。正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行文本匹配。在linux中,有两种流行的正则表达式引擎(POSIX可以认为是unix国际标准):
- POSIX基础正则表达式(basic regular expression, BRE)引擎
- POSIX扩展正则表达式(extended regular expression, ERE)引擎。
大多数linux工具都至少符合POSIX BRE引擎规范,能够识别该规范定义的所有模式符号。遗憾的是,有些工具(比如sed编辑器)只符合BRE引擎规范的子集。这是处于速度方面的考虑导致的,因为sed编辑器希望能尽可能快地处理数据流中的文本。gawk程序用ERE引擎来处理它的正则表达式模式。
1.定义BRE模式
第一条原则:正则表达式模式都区分大小写。 在正则表达式中,你不用写出整个单词。只要定义的文本出现在数据流中,正则表达式就能够匹配。
$ echo "The books are expensive" | sed -n '/book/p'
This books are expensive
尽管数据流中的文本是books,但数据中含有正则表达式book,因此正则表达式模式跟数据匹配。 你也不用局限于在正则表达式中只用单个单词,可以在表达式中使用空格和数字。
$ echo "This is line number 1" | sed -n '/ber 1/p'
This is line number 1
$
在正则表达式中,空格和其他的字符并没有什么区别。
# 匹配含有两个空格的行
$ cat data.txt
This is a normal line of text.
This is a line with too many spaces.
$ sed -n '/ /p' data.txt
This is a line with too many spaces.
特殊字符:在正则表达式模式中使用文本字符时,有些事情值得注意。在正则表达式中定义文本字符时有一些特例。有些字符在正则表达式中有特殊的含义。如果要在文本模式中使用这些字符,结果会超出你的意料。正则表达式识别的特殊字符包括:()[]{}^$+.?|*/
。如果要用某个特殊字符作为文本字符,就必须转义。在转义特殊字符时,你需要在它前面加一个特殊字符来告诉正则表达式引擎应该将接下来的字符当作普通的文本字符。这个特殊字符就是反斜线。
$ echo "3 / 2" | sed -n '///p'
sed -e expression $1, char 2: No previous regular expression
要使用正斜线,也需要进行转义:
$ echo "3 / 2" | sed -n '/\//p'
3 / 2
锚字符:默认情况下,当指定一个正则表达式模式时,只要模式出现在数据流中的任何地方,它就能匹配。有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾。分别是^和$。
dach@dachHost:~$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test
dach@dachHost:~$ echo "This ^ is a test" | sed -n '/s \^/p'
This ^ is a test
如果指定正则表达式模式时只用了^字符,就不需要使用反斜线来转义。但如果你在模式中先指定了^,其后还有其他一些文本,那么你必须在^前用转义字符。
删除文本中所有的空白符:
$ cat data.txt
This is one test line.
This is another test line.
$ sed '/^$/d' data.txt
点号字符:特殊字符点号用来匹配除换行符之外的任意单个字符。它必须匹配一个字符,如果在点号字符的位置没有字符,那么模式就不成立。
字符组:点号特殊字符在匹配某个字符位置上的任意字符时很有用。但如果你想要限定待匹配的具体字符呢?在正则表达式中,这称为字符组(character class)。可以定义用来匹配文本模式中某个位置的一组字符。如果字符组中的某个字符出现在了数据流中,那它就匹配了该模式。
使用方括号来定义一个字符组。方括号中包含所有你希望出现在该字符组中的字符。然后你可以在模式中使用整个组,就跟使用其他通配符一样。这需要一点时间来适应,但一旦你适应了,效果可是令人惊叹的。
在正则表达式模式中,也可以反转字符组的作用。可以寻找组中没有的字符,而不是去寻找组中含有的字符。要这么做的话,只要在字符组的开头加个脱字符。
$ sed -n '/[^ch]at/p' data.txt
This test is at line four.
除了定义自己的字符组外,BRE还包含了一些特殊的字符组,可用来匹配特定类型的字符。
组 | 描述 |
---|---|
[[:alpha:]] | 匹配任意字母字符,不管是大写还是小写 |
[[:alnum:]] | 匹配任意字母数字字符0~9,A~Z或a~z |
[[:blank:]] | 匹配空格或制表符 |
[[:digit:]] | 匹配0~9之间的数字 |
[[:lower:]] | 匹配小写字母字符a~z |
[[:print:]] | 匹配任意可打印字符 |
[[:punct:]] | 匹配标点符号 |
[[:space:]] | 匹配任意空白字符:空格、制表符、NL、FF、VT和CR |
[[:upper:]] | 匹配任意大写字母字符A~Z |
星号:在字符后面放置星号表明该字符必须在匹配模式的文本中出现0次或多次。
2. 扩展正则表达式ERE
POSIX ERE模式包含了一些可供linux应用和工具使用的额外符号。gawk程序能够识别ERE模式,但sed编辑器不能。gawk程序可以使用大多数扩展正则表达式模式符号,并且能提供一些额外过滤功能,而这些功能都是sed编辑器所不具备的。但正因为如此,gawk程序在处理数据流时通常才比较慢。
问号:问号表明前面的字符可以出现0次或1次,但只限于此。它不会匹配多次出现的字符。
加号:加号表明前面的字符可以出现1次或多次,但必须至少出现1次。如果该字符没有出现,那么模式就不会匹配。
花括号:ERE中的花括号允许你为可重复的正则表达式指定一个上限。这通常称为间隔。可以用两种格式来指定区间: m: 正则表达式准确出现m次。 m,n 正则表达式至少出现m次,至多n次。
默认情况下,gawk程序不会识别正则表达式间隔。必须指定gawk程序的–re-interval选项才能识别正则表达式间隔。 最新版本的gawk已经在不指定–re-interval选项的情况下也可以使用{n,m} 但是,awk程序没有–re-interval这个选项。
$ echo "bet" | gawk --re-interval '/be{1}t/{print $0}'
管道符号:管道符号允许你在检查数据时,用逻辑or方式指定正则表达式引擎要用的两个或多个模式。如果任何一个模式匹配了数据流文本,文本就通过测试。如果没有模式匹配,则数据流文本匹配失败。expr1|expr2|...
。
$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
表达式分组: 正则表达式模式也可以用圆括号进行分组。
$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
4. 实战
目录文件计数:
#!/bin/bash
# count number of files in your PATH
mypath=$(echo $PATH | sed 's/:/ /g')
count=0
for directory in $mypath
do
check=$(ls $directory)
for item in $check
do
count=$[ $count + 1 ]
done
echo "$directory - $count"
count=0
done
验证电话号码:
#!/bin/bash
# script to filter out bad phone numbers
awk '/^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$/{print $0}'
解析邮箱地址
#!/bin/bash
# script to filter oiut bad email address
awk '/^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/{print $0}'
本文发表于 0001-01-01,最后修改于 0001-01-01。
本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。