正则表达式是一个非常重要的用于文本操作的工具。

0.参考文献

《Linux命令行大全》 [美] William E. Shotts. Jr 著 郭光伟 郝记生 译, 人民邮电出版社

更多有用的Linux知识详解,可参加博主的Linux学习导航页

1.什么是正则表达式

正则表达式是一种符号表示法,用于识别文本模式。在某种程度上,它们类似于匹配文件和路径名使用的shell通配符
许多命令行工具和大多数编程语言都支持正则表达式,以此来解决文本操作方面的问题。但不同的编程语言之间,正则表达式会略有不同。
方便起见,我们将正则表达式的讨论限定在POSIX标准中。

2. grep–文本搜索

处理正则表达式的主要程序是grep。grep程序名字源于"global regular expression print"。实际上,grep搜索文本中与指定正则表达式匹配的行,并将结果送至标准输出。
grep程序的语法为

grep [options] regex [file ...]

表1 grep常用的选项

选项功能描述
-i忽略大小写。也可以用–ignore-case指定
-v不匹配。正常情况下,grep会输出匹配行,而该选项可使grep输出不包含匹配项的所有行,也可以用–invert-match指定。
-c输出匹配项数目(如果有-v选项,就输出不匹配项的数目)而不是直接输出匹配行自身,也可使用–count指定
-l输出匹配项文件名而不是直接输出匹配行自身。也可以用–files-with-matches指定
-L与-l选项类似,但输出的是不含匹配项的文件名,可以用–files-without-match指定
-n在每个匹配行前面加上该行在文件内的行号。也可以用–line-number指定
-h进行多文件搜索时,抑制文件名输出。也可用–no-filename指定

我们创建几个示例文件来进行搜索

$ ls /bin > dirlist-bin.txt
$ ls /usr/bin > dirlist-usr-bin.txt
$ ls /sbin/ > dirlist-sbin.txt
$ ls /usr/sbin > dirlist-usr-sbin.txt
$ ls dirlist*.txt
dirlist-bin.txt  dirlist-sbin.txt  dirlist-usr-bin.txt  dirlist-usr-sbin.txt

我们可以对文件列表执行简单的搜索

$ grep bzip dirlist*.txt
dirlist-bin.txt:bzip2
dirlist-bin.txt:bzip2recover

上个例子中,grep命令会搜索所有的文件,以查找字符串bzip,并找到了两个匹配项,并且这两个匹配项都在文件dirlist-bin.txt中。
如果我们只对包含匹配项的文件感兴趣而不是对匹配项本身感兴趣,可以指定-l选项。

$ grep -l bzip dirlist*.txt
dirlist-bin.txt

相反,如果只想查看那些不包含匹配项的文件,则可以用如下命令行

$ grep -L bzip dirlist*.txt
dirlist-sbin.txt
dirlist-usr-bin.txt
dirlist-usr-sbin.txt

3.元字符和文字

字符串bzip中的字符都是文字字符(literal character),即它们只能与自身进行匹配。除了文字字符,正则表达式还可以包含用于指定更为复杂的匹配的元字符。正则表达式的元字符包含以下字符

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

4.任意字符

接下来要讨论的第一个元字符是**“点”字符或者句点字符。该字符用于匹配任意字符**。

$ grep -h '.zip' dirlist*.txt
bunzip2
bzip2
bzip2recover
gunzip
gzip
funzip
gpg-zip
unzip
unzipsfx

上述命令行,搜索到所有匹配正则表达式.zip的命令行。但其输出中没有包含zip程序,这是因为正则表达式中的“.”元字符将匹配长度增加到了4个字符。而“zip”只包含3个字符。此时,文件扩展名中的“.”符号也被当做**“任意字符”**处理了。

5.锚

插入符(^)和美元符号($)在正则表达式中被当做,也就是说正则表达式只与行的开头(^)或是末尾($)的内容进行匹配比较

$ grep -h '^zip' dirlist*.txt
zipdetails
zipgrep
zipinfo
$ grep -h 'zip$' dirlist*.txt
gunzip
gzip
funzip
gpg-zip
unzip
$ grep -h '^zip$' dirlist*.txt
zip

6.中括号表达式和字符类

中括号除了可以用于匹配正则表达式中给定位置的任意字符外,还可以用于匹配指定字符集的单个字符
如下命令行则利用一个两个字母组成的字符集,用于匹配包含bzip和gzip字符串的文本行。

$ grep -h '[bg]zip' dirlist*.txt
bzip2
bzip2recover
gzip

一个字符集可以包含任意数目的字符,并且当元字符放置到中括号时,会失去它们的特殊意义
两种情况下,在中括号中使用元字符,会有不同的意义。第一个是插入符(^),其在中括号中表示否定。另外一个是连字符(-),它表示字符范围。

6.1 否定

如果中括号内的第一个字符是插入符(^),那么剩下的字符则被当做不应该在指定位置出现的字符集。

$ grep -h '[^bg]zip' dirlist*.txt
bunzip2
gunzip
funzip
gpg-zip
unzip
unzipsfx

以上例子通过否定操作,得到那些包含zip字符串但zip前面既不是b也不是g的所有程序。注意,此时zip仍没有出现在结果列表中,可见否定时,字符集仍然需要在指定位置有对应字符。
只有在插入字符(^)在中括号表达式中第一个字符时才会被当做否定符。如果不是,则被转义为普通字符。

6.2 传统字符范围

如果我们希望查找文件名义大写字母开头的文件,可以用以下简单方法:

$ grep -h '^[A-Z]' dirlist*.txt
MAKEDEV
ControlPanel
Mail
NF
VGAuthService
X
X11
Xorg

再例如,下面例子可以匹配以字母和数字开头的所有文件名

$ grep -h '^[A-Za-z0-9]' dirlist*.txt

如果我们真要查找含有连字符“-”的文件,可以在中括号中第一个字符使用连字符

$ grep -h '[-AZ]' dirlist*.txt

6.3 POSIX字符类

表2 POSIX字符类

字符类描述
[:alnum:]字母字符和数字字符;在ASCII码中,与[A-Za-z0-9]等效
[:word:]基本与[:alnum:]一样,只是多了个下划线字符(_)
[:alpha:]字母字符
[:blank:]包括空格和制表符
[:cntrl:]ASCII控制码;包含ASCII字符0~31以及127
[:digit:]数字0~9
[:graph:]可见字符;在ASCII中,包含字符33~126
[:lower:]小写字母
[:punct:]标点符号字符
[:print:]可打印字符;包括[:graph:]中所有字符再加上空格字符
[:space:]空白字符如空格符、制表符、回车符、换行符、垂直制表符以及换页符
[:upper:]大写字母
[:xdigit:]用于表示十六进制的字符

7. POSIX基本正则表达式和扩展正则表达式

POSIX规范将正则表达式分为两种:基本正则表达式(BRE)扩展正则表达式(ERE)
BRE和ERE的不同仅仅在于元字符的不同。在BRE方式中,只承认^、$、.、[、]、*这些元字符,所有的其它字符都被识别为文字字符。而ERE中,则添加了(、)、{、}、?、+、|等元字符。
由于下面要讨论的特性是ERE的一部分,所以需要使用不一样的grep。一般是执行egrep程序,但是GNU版本的grep可以运行-E选项以支持ERE方式。

8.或选项

括号表达式可以从指定字符集中匹配单一字符,而或选项则用于从字符集或正则表达式集中寻找匹配项

x$ echo "AAA" | grep AAA
AAA
$ echo "AAA" | grep BBB
$ echo "AAA" | grep -E 'AAA|BBB'
AAA

这里出现了’AAA|BBB’正则表达式,含义是“匹配字符串AAA或者字符串BBB”。
注意,此时使用扩展选项,因此需要为grep增加-E选项,并且将正则表达式引起来防止shell将元字符“|”当做管道处理。
另外,或选项不局限于两种,例如

$ echo "AAA" | grep -E 'AAA|BBB|CCC'
AAA

为了将或选项与其它正则表达式符号结合使用,可以用“()”将或选项的所有元素与其它符号隔开。

$ grep -Eh '^(bz|gz|zip)' dirlist*.txt

以上表达式的含义是匹配文件名义bz、gz或是zip开头的文件。如果不含有括号

$ grep -Eh '^bz|gz|zip' dirlist*.txt

含义就变成了以bz开头或者是包含gz和zip的文件。

9.限定符

扩展正则表达式(ERE)提供多种方法指定某元素匹配的次数

9.1 ?—匹配某元素0次或1次

该限定符实际上意味着“前面的元素可选”。
例如检查某电话号的有效性,必须是下面格式(nnn) nnn-nnnn和nnn nnn-nnnn中的一种,其中n是数值。
可以构造下面的正则表达式:
^(?[0-9][0-9][0-9])? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$
表示括号字符只能匹配一次或零次。反斜杠告诉shell括号已经转义。

$ echo "(555) 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
(555) 123-4567
$ echo "555 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
555 123-4567
$ echo "AAA 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'

9.2 *—匹配某元素多次或零次

与“?”元字符类似,“*”用于表示一个可选择的条目。然而,与“?”不同,该条目可以出现多次,而不仅仅是一次。
例如,我们想知道一串字符是否以大写字母开头而以句号结束,并且中间内容是任意数目的大小写字母和空格。那么可以使用如下正则表达式。
[[:upper:]][[:upper:][:lower:] ]*.
以上表达式包含了三个条目:包含[:upper:]字符类的中括号表达式、包含[:upper:]和[:lower:]两个字符类以及一个空格的空括号表达式、用反斜杠转义过的圆点字符。第二个条目中紧跟“*”元字符,所以只要句子的第一个字母是大写字母,后面不管会出现多少数目的大小写字母都无关紧要。

$ echo "This works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This works.
$ echo "This Works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This Works.
$ echo "this does not" | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'

9.3 ±–匹配某元素一次或多次

'+‘元字符与’*‘非常类似,只是’+'要求置于其前面的元素至少出现一次
示例如下,该正则表达式用于匹配由单个空格分隔的一个或者多个字母字符组成的行。
^([[:alpha:]]+ ?)+$

$ echo "This that" | grep -E '^([[:alpha:]]+ ?)+$'
This that
$ echo "a b c" | grep -E '^([[:alpha:]]+ ?)+$'
a b c
$ echo "a b 9" | grep -E '^([[:alpha:]]+ ?)+$'

$echo "a b  d" | grep -E '^([[:alpha:]]+ ?)+$'

9.4 {}—以指定次数匹配某元素

“{”和“}”元字符用于描述最小和最大匹配次数的需求。有四种方法
表3 指定匹配次数

指定项含义
{n}前面的元素恰好出现n次则匹配
{n,m}前面的元素出现次数在n~m次之间时则匹配
{n,}前面的元素出现次数超过n次则匹配
{,m}前面的元素出现次数不超过m次则匹配

例如前面电话号码可以改为
“^(?[0-9]{3})? [0-9]{3}-[0-9]{4}$”

10.正则表达式的应用

10.1 使用grep

以上已经展示很多了

10.2 用find查找文件名

find命令的test选项可以用正则表达式表示,与grep有所不同,grep命令是搜索那些只包含与指定表达式匹配的字符串的行,而find则要求文件名与指定表达式完全一致
例如

$ find . -regex '.*[^-_-./0-9a-zA-Z].*'

10.3 用locate查找文件

locate命令既支持基本正则表达式(–regexp)选项,也支持扩展正则表达式(–regex选项)。利用locate,可以完成之前对dirlist文件所做的许多操作。

$  locate --regex 'bin/(z|gz|zip)'

10.4 利用less和vim命令搜索文本

less和vim采用同样的方式进行文本搜索。按下“/”键后输入正则表达式,即开始进行搜索。

GitHub 加速计划 / li / linux-dash
6
1
下载
A beautiful web dashboard for Linux
最近提交(Master分支:3 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐