正则表达式是你所定义的模式模板, Linux工具可以用它来过滤文本。 Linux 工具(比如sed编辑器或gawk程序)能够在处理数据时使用正则表达式对数据进行模式匹配。如果数据匹配模式,它就会被接受并进一步处理;如果数据不匹配模式,它就会被滤掉。
正则表达式模式利用通配符来描述数据流中的一个或多个字符。正则表达式模式含有文本或特殊字符,为sed编辑器和gawk程序定义了一个匹配数据时采用的模板。可以在正则表达式中使用不同的特殊字符来定义特定的数据过滤模式。
正则表达式是通过正则表达式引擎实现的。正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行文本匹配。
在Linux中,有两种流行的正则表达式引擎:
在Linux中,常用文本处理工具:
正则表达式并不关心模式在数据流中的位置。它也不关心模式出现了多少次。一旦正则表达式匹配了文本字符串中任意位置上的模式,它就会将该字符串传回Linux工具。
重要的是记住正则表达式对匹配的模式非常挑剔。第一条原则就是:正则表达式模式都区分大小写。这意味着它们只会匹配大小写也相符的模式。
在正则表达式中,你不用写出整个单词。只要定义的文本出现在数据流中,正则表达式就能够匹配。
echo "The books are expensive" | sed -n '/book/p'
The books are expensive
不用局限于在正则表达式中只用单个文本单词,可以在正则表达式中使用空格和数字。
echo "This is line number 1" | sed -n '/ber 1/p'
This is line number 1
这是用来查看文本文件中空格问题的好办法。
sed -n '/ /p' data1
This is a line with too many spaces.
在正则表达式中定义文本字符时有一些特例。有些字符在正则表达式中有特别的含义。
正则表达式识别的特殊字符包括:
.*[]^${}\+?|()
如果要用某个特殊字符作为文本字符,就必须转义。在转义特殊字符时,你需要在它前面加一个特殊字符来告诉正则表达式引擎应该将接下来的字符当作普通的文本字符。这个特殊字符就是反斜线(\)。
sed -n '/\$/p' data2
The cost is $4.00
echo "\ is a special character" | sed -n '/\\/p'
\ is a special character
尽管正斜线不是正则表达式的特殊字符,但如果它出现在sed编辑器或gawk程序的正则表达式中,你就会得到一个错误。
echo "3 / 2" | sed -n '///p'
sed: -e expression #1, char 2: No previous regular expression
要使用正斜线,也需要进行转义。
echo "3 / 2" | sed -n '/\//p'
3 / 2
默认情况下,当指定一个正则表达式模式时,只要模式出现在数据流中的任何地方,它就能匹配。有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾。
锁定在行首
脱字符(^)定义从数据流中文本行的行首开始的模式。如果模式出现在行首之外的位置,正则表达式模式则无法匹配。
echo "The book store" | sed -n '/^book/p'
echo "Books are great" | sed -n '/^Book/p'
Books are great
如果你将脱字符放到模式开头之外的其他位置,那么它就跟普通字符一样,不再是特殊字符了:
echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test
锁定在行尾
特殊字符美元符($)定义了行尾锚点。将这个特殊字符放在文本模式之后来指明数据行必须以该文本模式结尾。
echo "This is a good book" | sed -n '/book$/p'
This is a good book
echo "This book is good" | sed -n '/book$/p'
组合锚点
假定你要查找只含有特定文本模式的数据行。
sed -n '/^this is a test$/p' data4
this is a test
将两个锚点直接组合在一起,之间不加任何文本,这样过滤出数据流中的空白行。
从文档中删除空白行的有效方法。
sed '/^$/d' data5
This is one test line.
This is another test line.
特殊字符点号用来匹配除换行符之外的任意单个字符。它必须匹配一个字符,如果在点号字符的位置没有字符,那么模式就不成立。
cat data6
This is a test of a line.
The cat is sleeping.
That is a very nice hat.
This test is at line four.
at ten o'clock we'll go home.
sed -n '/.at/p' data6
The cat is sleeping.
That is a very nice hat.
This test is at line four.
点号特殊字符在匹配某个字符位置上的任意字符时很有用。但如果你想要限定待匹配的具体字符呢?在正则表达式中,这称为字符组。可以定义用来匹配文本模式中某个位置的一组字符。字符组中必须有个字符来匹配相应的位置。
sed -n '/[ch]at/p' data6
The cat is sleeping.
That is a very nice hat.
echo "Yes" | sed -n '/[Yy]es/p'
Yes
echo "yes" | sed -n '/[Yy]es/p'
yes
echo "Yes" | sed -n '/[Yy][Ee][Ss]/p'
Yes
echo "yEs" | sed -n '/[Yy][Ee][Ss]/p'
yEs
echo "yeS" | sed -n '/[Yy][Ee][Ss]/p'
yeS
字符组不必只含有字母,也可以在其中使用数字。
sed -n '/[0123]/p' data7
This line has 1 number on it.
This line a number 2 on it.
字符组的一个极其常见的用法是解析拼错的单词,比如用户表单输入的数据。
sed -n '
/maint[ea]n[ae]nce/p
/sep[ea]r[ea]te/p
' data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.
通过排除型字符组,正则表达式模式会匹配c或h之外的任何字符以及文本模式。
sed -n '/[^ch]at/p' data6
This test is at line four.
可以用单破折线符号在字符组中表示字符区间。只需要指定区间的第一个字符、单破折线以及区间的最后一个字符就行了。
sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8
60633
46201
45902
还可以在单个字符组指定多个不连续的区间。
sed -n '/[a-ch-m]at/p' data6
The cat is sleeping.
That is a very nice hat.
一些固定的特殊字符组。
组 描 述
[[: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
echo "abc" | sed -n '/[[:alpha:]]/p'
abc
echo "abc123" | sed -n '/[[:digit:]]/p'
abc123
echo "This is, a test" | sed -n '/[[:punct:]]/p'
This is, a test
在字符后面放置星号表明该字符必须在匹配模式的文本中出现0次或多次。
echo "ik" | sed -n '/ie*k/p'
ik
echo "iek" | sed -n '/ie*k/p'
iek
echo "ieek" | sed -n '/ie*k/p'
ieek
另一个方便的特性是将点号特殊字符和星号特殊字符组合起来。这个组合能够匹配任意数量的任意字符。它通常用在数据流中两个可能相邻或不相邻的文本字符串之间。
echo "this is a regular pattern expression" | sed -n '
> /regular.*expression/p'
this is a regular pattern expression
星号还能用在字符组上。它允许指定可能在文本中出现多次的字符组或字符区间。
echo "bt" | sed -n '/b[ae]*t/p'
bt
echo "bat" | sed -n '/b[ae]*t/p'
bat
echo "bet" | sed -n '/b[ae]*t/p'
bet
echo "btt" | sed -n '/b[ae]*t/p'
btt
gawk程序能够识别ERE模式,但sed编辑器不能。
记住, sed编辑器和gawk程序的正则表达式引擎之间是有区别的。 gawk程序可以使用大多数扩展正则表达式模式符号,并且能提供一些额外过滤功能,而这些功能都是sed编辑器所不具备的。但正因为如此, gawk程序在处理数据流时通常才比较慢。
问号表明前面的字符可以出现0次或1次,但只限于此。它不会匹配多次出现的字符。
echo "bt" | gawk '/be?t/{print $0}'
bt
echo "bet" | gawk '/be?t/{print $0}'
bet
echo "beet" | gawk '/be?t/{print $0}'
echo "beeet" | gawk '/be?t/{print $0}'
echo "bt" | gawk '/b[ae]?t/{print $0}'
bt
echo "bat" | gawk '/b[ae]?t/{print $0}'
bat
echo "bot" | gawk '/b[ae]?t/{print $0}'
加号表明前面的字符可以出现1次或多次,但必须至少出现1次。如果该字符没有出现,那么模式就不会匹配。
echo "beeet" | gawk '/be+t/{print $0}'
beeet
echo "beet" | gawk '/be+t/{print $0}'
beet
echo "bet" | gawk '/be+t/{print $0}'
bet
echo "bt" | gawk '/be+t/{print $0}'
echo "bt" | gawk '/b[ae]+t/{print $0}'
echo "bat" | gawk '/b[ae]+t/{print $0}'
bat
echo "bet" | gawk '/b[ae]+t/{print $0}'
bet
echo "beat" | gawk '/b[ae]+t/{print $0}'
beat
echo "beet" | gawk '/b[ae]+t/{print $0}'
beet
echo "beeat" | gawk '/b[ae]+t/{print $0}'
beeat
{ }花括号允许你为可重复的正则表达式指定一个上限。这通常称为间隔。
默认情况下, gawk程序不会识别正则表达式间隔。必须指定gawk程序的 --re-interval 命令行选项才能识别正则表达式间隔。
echo "bet" | gawk --re-interval '/be{1}t/{print $0}'
bet
echo "bt" | gawk --re-interval '/be{1,2}t/{print $0}'
echo "bet" | gawk --re-interval '/be{1,2}t/{print $0}'
bet
echo "bt" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
echo "bat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bat
echo "bet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bet
管道符号允许你在检查数据流时,用逻辑OR方式指定正则表达式引擎要用的两个或多个模式。如果任何一个模式匹配了数据流文本,文本就通过测试。如果没有模式匹配,则数据流文本匹配失败。
echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
查找正则表达式cat或dog。正则表达式和管道符号之间不能有空格,否则它们也会被认为是正则表达式模式的一部分。
管道符号两侧的正则表达式可以采用任何正则表达式模式(包括字符组)来定义文本。
echo "He has a hat." | gawk '/[ch]at|dog/{print $0}'
正则表达式模式也可以用圆括号进行分组。当你将正则表达式模式分组时,该组会被视为一个标准字符。
echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday
将分组和管道符号一起使用来创建可能的模式匹配组是很常见的做法。
echo "cat" | gawk '/(c|b)a(b|t)/{print $0}'
cat
echo "cab" | gawk '/(c|b)|(b|t)/{print $0}'
cab
[root@ufo130 ~]# cat countfiles
#!/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
[root@ufo130 ~]# cat isphone
#!/bin/bash
# script to filter out bad phone numbers
gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\¬
[0-9]{3}( |-|\.)[0-9]{4}/{print $0}'
echo "317-555-1234" | ./isphone
^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$