2. 基本语法
我们知道 C 的变量和 Shell 脚本变量的定义和使用方法很不相同,表达能力也不相同,C 的变量有各种类型,而 Shell 脚本变量都是字符串。同样道理,各种工具和编程语言所使用的正则表达式规范的语法并不相同,表达能力也各不相同,有的正则表达式规范引入很多扩展,能表达更复杂的模式,但各种正则表达式规范的基本概念都是相通的。本节介绍 egrep(1) 所使用的正则表达式,它大致上符合 POSIX 正则表达式规范,详见 regex(7) (看这个 man page 对你的英文绝对是很好的锻炼)。希望读者仿照上一节的例子,一边学习语法,一边用 egrep 命令做实验。
表 32.1. 字符类
| 字符 | 含义 | 举例 |
|---|---|---|
. | 匹配任意一个字符 | abc. 可以匹配 abcd 、 abc9 等 |
[] | 匹配括号中的任意一个字符 | [abc]d 可以匹配 ad 、 bd 或 cd |
- | 在 [] 括号内表示字符范围 | [0-9a-fA-F] 可以匹配一位十六进制数字 |
^ | 位于 [] 括号内的开头,匹配除括号中的字符之外的任意一个字符 | [^xy] 匹配除 xy 之外的任一字符,因此 [^xy]1 可以匹配 a1 、 b1 但不匹配 x1 、 y1 |
[[:xxx:]] | grep 工具预定义的一些命名字符类 | [[:alpha:]] 匹配一个字母, [[:digit:]] 匹配一个数字 |
表 32.2. 数量限定符
| 字符 | 含义 | 举例 |
|---|---|---|
? | 紧跟在它前面的单元应匹配零次或一次 | [0-9]?\.[0-9] 匹配 0.0 、 2.3 、 .5 等,由于 . 在正则表达式中是一个特殊字符,所以需要用 \ 转义一下,取字面值 |
+ | 紧跟在它前面的单元应匹配一次或多次 | [a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+ 匹配 email 地址 |
* | 紧跟在它前面的单元应匹配零次或多次 | [0-9][0-9]* 匹配至少一位数字,等价于 [0-9]+ , [a-zA-Z_]+[a-zA-Z_0-9]* 匹配 C 语言的标识符 |
{N} | 紧跟在它前面的单元应精确匹配 N次 | [1-9][0-9]{2} 匹配从 100 到 999 的整数 |
{N,} | 紧跟在它前面的单元应匹配至少 N 次 | [1-9][0-9]{2,} 匹配三位以上(含三位)的整数 |
{,M} | 紧跟在它前面的单元应匹配最多 M 次 | [0-9]{,1} 相当于 [0-9]? |
{N,M} | 紧跟在它前面的单元应匹配至少 N 次,最多 M 次 | [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} 匹配 IP 地址 |
再次注意 grep 找的是包含某一模式的行,而不是完全匹配某一模式的行。再举个例子,如果文本文件的内容是
aaabc
aad
efg查找 a* 这个模式的结果是三行都被找出来了
$ egrep 'a*' testfile
aabc
aad
efga* 匹配 0 个或多个 a ,而第三行包含 0 个 a ,所以也包含了这一模式。单独用 a* 这样的正则表达式做查找没什么意义,一般是把 a* 作为正则表达式的一部分来用。
表 32.3. 位置限定符
| 字符 | 含义 | 举例 |
|---|---|---|
^ | 匹配行首的位置 | ^Content 匹配位于一行开头的 Content |
$ | 匹配行末的位置 | ;$ 匹配位于一行结尾的 ; 号, ^$ 匹配空行 |
\< | 匹配单词开头的位置 | \<th 匹配 ... this ,但不匹配 ethernet 、 tenth |
\> | 匹配单词结尾的位置 | p\> 匹配 leap ... ,但不匹配 parent 、 sleepy |
\b | 匹配单词开头或结尾的位置 | \bat\b 匹配 ... at ... ,但不匹配 cat 、 atexit 、 batch |
\B | 匹配非单词开头和结尾的位置 | \Bat\B 匹配 battery ,但不匹配 ... attend 、 hat ... |
位置限定符可以帮助 grep 更准确地查找,例如上一节我们用 [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} 查找 IP 地址,找到这两行
192.168.1.1
1234.234.04.5678如果用 ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ 查找,就可以把 1234.234.04.5678 这一行过滤掉了。
表 32.4. 其它特殊字符
| 字符 | 含义 | 举例 |
|---|---|---|
\ | 转义字符,普通字符转义为特殊字符,特殊字符转义为普通字符 | 普通字符 < 写成 \< 表示单词开头的位置,特殊字符 . 写成 \. 以及 \ 写成 \\ 就当作普通字符来匹配 |
() | 将正则表达式的一部分括起来组成一个单元,可以对整个单元使用数量限定符 | ([0-9]{1,3}\.){3}[0-9]{1,3} 匹配 IP 地址 |
| | 连接两个子表达式,表示或的关系 | n(o|either)匹配no或neither |
以上介绍的是 grep 正则表达式的 Extended 规范,Basic 规范也有这些语法,只是字符 ?+{}|() 应解释为普通字符,要表示上述特殊含义则需要加 \ 转义。如果用 grep 而不是 egrep ,并且不加 -E 参数,则应该遵照 Basic 规范来写正则表达式。