Shell中的正则表达式(POSIX标准正则表达式)

注:本文为《The Linux Command Line》–William Shotts书中的正则表达式章节的笔记,引用了其中的大部分内容,转载请注明本段文字

POSIX标准的正则表达式

正则表达式是一种符号表示法,被用来识别文本模式。许多命令行工具和大多数的编程语言都支持正则表达式,以此来帮助解决文本操作问题。然而,并不是所有的正则表达式都是一样的,本文将会限定 POSIX 标准中描述的正则表达式,大部分命令行工具都使用这一标准。

正则表达式的构成

元字符和原义字符 (Metacharacters And Literals)
对于原义字符,仅匹配其本身
对于元字符,在匹配时有特殊含义
元字符包括

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

其它所有字符都被认为是原义字符。在个别情况下,反斜杠会被用来创建元序列,元字符也可以被转义为原义字符,而不是被解释为元字符。

两种正则表达式

POSIX 把正则表达式的实现分成了两类:
基本正则表达式(BRE)和扩展的正则表达式(ERE)
BRE 可以辨别以下元字符:

^ $ . [ ] *

其它的所有字符被认为是文本字符。ERE 添加了以下元字符(以及与其相关的功能):

( ) { } ? + |

使用注意:在 BRE 中,字符“(”,“)”,“{”,和“}”用反斜杠转义后,被看作是元字符, 相反在 ERE 中,在任意元字符之前加上反斜杠会导致其被看作是一个文本字符。

基本正则表达式

. 用于匹配任意一个字符

如果我们在正则表达式中包含它,它将会匹配在此位置的任意一个字符。注意:任意一个字符不代表可以为空;匹配对象中的原点也可以成为匹配项,因为原点也是普通字符。
示例:

[me@linuxbox ~]$ grep -h '.zip' dirlist.txt
bunzip2
bzip2
bzip2recover
gunzip
gzip
txt.zip
^、$ 用于匹配锚点

在正则表达式中,插入符号和美元符号被看作是锚点。这意味着正则表达式只有在文本行的开头或末尾被找到时,才算发生一次匹配。
示例-匹配每行开头包含zip的行:

[me@linuxbox ~]$ grep -h '^zip' dirlist.txt
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit

示例-匹配每行开头包含zip的行:
[me@linuxbox ~]$ grep -h ‘zip$’ dirlist.txt

gunzip
gzip
funzip
gpg-zip
preunzip
prezip
unzip
zip

示例-匹配行首和行尾同时包含zip的行

[me@linuxbox ~]$ grep -h '^zip$' dirlist.txt
zip
#本例特殊,zip独占一行

示例-匹配空行

[me@linuxbox ~]$ grep -h '^$' dirlist.txt
[] 用于匹配字符集中的一个,-用于表示一个字符集范围

通过使用中括号表达式,我们也能够从一个指定的字符集合中匹配单个字符。
示例:

[me@linuxbox ~]$ grep -h '[bg]zip' dirlist.txt
bzip2
bzip2recover
gzip

[]还可以借助 - 来表示一个字符范围
示例:

[me@linuxbox ~]$ grep -h '^[ABCDEFGHIJKLMNOPQRSTUVWXZY]' dirlist.txt
#等同于
[me@linuxbox ~]$ grep -h '^[A-Z]' dirlist.txt

#匹配了所有以字母和数字开头的行
[me@linuxbox ~]$ grep -h '^[A-Za-z0-9]' dirlist.txt

如果想让 - 作为普通字符被匹配,则应当将 - 成为表达式的第一个字符
示例:

[me@linuxbox ~]$ grep -h '[-AZ]' dirlist.txt

关于[A-Z]表示的匹配范围不一致的解释

其可能代表这样的字典
ABCDEFGHIJKLMNOPQRSTUVWXYZ
也可能代表
aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
确保使用第一种
[me@linuxbox ∼]$ export LANG=POSIX
永久生效
把这条语句添加到你的.bashrc 文件
export LANG=POSIX

除了使用 - 表示范围,POSIX规定了一些常用的字符集

字符集说明
[:alnum:]字母数字字符。在 ASCII 中,等价于:[A-Za-z0-9]
[:word:]与 [:alnum:] 相同, 但增加了下划线字符。
[:alpha:]字母字符。在 ASCII 中,等价于:[A-Za-z]
[:blank:]包含空格和 tab 字符。
[:cntrl:]ASCII 的控制码。包含了 0 到 31,和 127 的 ASCII 字符。
[:digit:]数字 0 到 9
[:graph:]可视字符。在 ASCII 中,它包含 33 到 126 的字符。
[:lower:]小写字母。
[:punct:]标 点 符 号 字 符。 在 ASCII 中, 等 价 于:[-!”#$%&’()*+,./:;<=>?@[\]_‘
[:print:]可打印的字符。在 [:graph:] 中的所有字符,再加上空格字符。
[:space:]空白字符,包括空格、tab、回车、换行、vertical tab 和form feed. 在 ASCII 中,等价于:[ \t\r\n\v\f]
[:upper:]大写字母。
[:xdigit:]用来表示十六进制数字的字符。在 ASCII 中,等价于:[0-9A-Fa-f]

拓展正则表达式

|从多个表达式中选择匹配项目

扩展表达式的第一个特性叫做 alternation(交替),其是一款允许从一系列表达式之间选择匹配项
示例:

[me@linuxbox ~]$ echo "AAA" | grep -E 'AAA|BBB'
AAA
[me@linuxbox ~]$ echo "BBB" | grep -E 'AAA|BBB'
BBB
[me@linuxbox ~]$ echo "CCC" | grep -E 'AAA|BBB'
[me@linuxbox ~]$ echo "AAA" | grep -E 'AAA|BBB|CCC'
AAA
#为了把 alternation 和其它正则表达式元素结合起来,
#我们可以使用() 来分离 alternation。
[me@linuxbox ~]$ grep -Eh '^(bz|gz|zip)' dirlist.txt

限定符

? 用于限定匹配零个或一个元素

这个限定符意味着,使前面的元素可有可无。
例如要匹配下面两种形式的文本

(nnn) nnn-nnnn
nnn nnn-nnnn

示例

[me@linuxbox ~]$ 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
[me@linuxbox ~] $ 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
[me@linuxbox ~] $ 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]$'
[me@linuxbox ~]$

分析一下这个正则表达式

^\ (? [0-9] [0-9] [0-9])? [0-9] [0-9] [0-9]- [0-9][0-9][0-9][0-9]$

由于这是拓展表达式,圆括号是元字符,因此需要转义;^标志匹配开头,&标志匹配末尾;括号后面的问号表示括号可有可无

* 用于限定匹配零次或多次

匹配的字符可以出现任意多次,不仅是一次。
示例匹配XXX_file,规定X代表大写字母,可以出现零次或一次

[me@linuxbox ~]$ echo "ABC_file." | grep -E '[[:upper:]]*_file'
ABC_file
[me@linuxbox ~]$ echo "_file." | grep -E '[[:upper:]]*_file'
_file
+用于限定匹配一次或多次

+要求前面的元素至少出现一次匹配。
示例,只匹配那些由一个或多个字母字符组构成的文本行,字母字符之间由单个空格分开:

^([[:alpha:]]+ ?)+$
[me@linuxbox ~]$ echo "This that" | grep -E '^([[:alpha:]]+ ?)+$'
This that
[me@linuxbox ~]$ echo "a b c" | grep -E '^([[:alpha:]]+ ?)+$'
a b c
[me@linuxbox ~]$ echo "a b 9" | grep -E '^([[:alpha:]]+ ?)+$'
[me@linuxbox ~]$ echo "abc d" | grep -E '^([[:alpha:]]+ ?)+$'
[me@linuxbox ~]$
{ } 用于限定匹配特定个数的元素

{ 和 } 元字符都被用来表达要求匹配的最小和最大数目。它们可以通过四种方法来指定:

限定符意义
n匹配前面的元素,如果它确切地出现了 n 次。
n,m匹配前面的元素,如果它至少出现了 n 次,但是不多于 m次。
n,匹配前面的元素,如果它出现了 n 次或多于 n 次。
,m匹配前面的元素,如果它出现的次数不多于 m 次。

回到处理

(nnn) nnn-nnnn
nnn nnn-nnnn

的例子
利用{}可以将表达式简化为

^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$
[me@linuxbox ~]$ echo "(555) 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
(555) 123-4567

Shell中的正则表达式的运用

grep

不指定-E参数,则grep使用的是基本正则表达式,加上-E参数后使用拓展正则表达式
也可以使用egrep命令使用拓展正则表达式
示例

[me@linuxbox ~] $ for i in {1..10}; do echo "($ {RANDOM: 0:3}) $ {RANDOM: 0:3}- $ {RANDOM:
0:4}" >> phonelist.txt; done
[me@linuxbox ~]$ cat phonelist.txt
(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440
find

使用-regex参数来使用正则表达式来测试文件名
示例查找命名不规范的文件

#规定不在下列字符集中的字符均为不规范的命名
[-\_./0-9a-zA-Z]
[me@linuxbox ~]$ find . -regex '.*[^-\_./0-9a-zA-Z].*
locate

–regexb 基本正则表达式
–regex 拓展的正则表达式
示例

[me@linuxbox ~]$ locate --regex 'bin/(bz|gz|zip)'
/bin/bzcat
/bin/bzcmp
/bin/bzdiff
/bin/bzegrep
/bin/bzexe
/bin/bzfgrep
less、vim

按下/,输入正则表达式来查找字符。vim仅支持基本正则表达式

[me@linuxbox ~]$ less phonelist.txt
(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440
~
/^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值