正则表达式就是由一系列特殊字符组成的字符串, 其中每个特殊字符都被称为元字符, 这些元字符并不表示为它们字面上的含义, 而会被解释为一些特定的含义. 具个例子, 比如引用符号, 可能就是表示某人的演讲内容, 同上, 也可能表示为我们下面将要讲到的符号的元-含义. 正则表达式其实是由普通字符和元字符共同组成的集合, 这个集合用来匹配(或指定)模式.

一个正则表达式会包含下列一项或多项:

  • 一个字符集. 这里所指的字符集只包含普通字符, 这些字符只表示它们的字面含义. 正则表达式的最简单形式就是包含字符集, 而不包含元字符.

  • . 指定了正则表达式所要匹配的文本在文本行中所处的位置. 比如, ^, 和$就是锚.

  • 修饰符. 它们扩大或缩小(修改)了正则表达式匹配文本的范围. 修饰符包含星号, 括号, 和反斜杠.

正则表达式最主要的目的就是用于(RE)文本搜索与字符串操作. (译者注: 以下正则表达式也会被简称为RE.) RE能够匹配单个字符或者一个字符集 -- 即, 一个字符串, 或者一个字符串的一部分.

  • 星号 -- * -- 用来匹配它前面字符的任意多次, 包括0次.

    "1133*"匹配11 + 一个或多个3 + 也允许后边还有其他字符: 113, 1133, 111312, 等等.

  • 点 -- . -- 用于匹配任意一个字符, 除了换行符. [1]

    "13." 匹配13 + 至少一个任意字符(包括空格): 1133, 11333, 但不能匹配13 (因为缺少"."所能匹配的至少一个任意字符).

  • 脱字符号 -- ^ -- 匹配行首, 但是某些时候需要依赖上下文环境, 在RE中, 有时候也表示对一个字符集取反.

  • 美元符 -- $ -- 在RE中用来匹配行尾.

    "XXX$" 匹配行尾的XXX.

    "^$" 匹配空行.

  • 中括号 -- [...] -- 在RE中, 将匹配中括号字符集中的某一个字符.

    "[xyz]" 将会匹配字符x, y, 或z.

    "[c-n]" 匹配字符c到字符n之间的任意一个字符.

    "[B-Pk-y]" 匹配从BP, 或者从ky之间的任意一个字符.

    "[a-z0-9]" 匹配任意小写字母或数字.

    "[^b-d]" 将会匹配范围在bd之外的任意一个字符. 这就是使用^对字符集取反的一个实例. (就好像在某些情况下, !所表达的含义).

    将多个中括号字符集组合使用, 能够匹配一般的单词或数字. "[Yy][Ee][Ss]"能够匹配yes, Yes, YES, yEs, 等等. "[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]" 可以匹配社保码(Social Security number).

  • 反斜杠 -- \ -- 用来转义某个特殊含义的字符, 这意味着, 这个特殊字符将会被解释为字面含义.

    "\$"将会被解释成字符"$", 而不是RE中匹配行尾的特殊字符. 相似的, "\\"将会被解释为字符"\".

  • 转义"尖括号" -- \<...\> -- 用于匹配单词边界.

    尖括号必须被转义才含有特殊的含义, 否则它就表示尖括号的字面含义.

    "\<the\>" 完整匹配单词"the", 不会匹配"them", "there", "other", 等等.

     

    bash$ cat textfile
    This is line 1, of which there is only one instance.
    This is the only instance of line 2.
    This is line 3, another line.
    This is line 4.



    bash$ grep 'the' textfile
    This is line 1, of which there is only one instance.
    This is the only instance of line 2.
    This is line 3, another line.



    bash$ grep '\<the\>' textfile
    This is the only instance of line 2.
  • 扩展的正则表达式. 添加了一些额外的匹配字符到基本集合中. 用于egrep, awk, 和Perl.

  • 问号 -- ? -- 匹配它前面的字符, 但是只能匹配1次或0次. 通常用来匹配单个字符.

  • 加号 -- + -- 匹配它前面的字符, 能够匹配一次或多次. 与前面讲的*号作用类似, 但是不能匹配0个字符的情况.

      1 # GNU版本的sed和awk能够使用"+",
    2 # 但是它需要被转义一下.

    4 echo a111b | sed -ne '/a1\+b/p'
    5 echo a111b | grep 'a1\+b'
    6 echo a111b | gawk '/a1+b/'
    7 # 上边3句的作用相同.

    9 # 感谢, S.C.
  • 转义"大括号" -- \{ \} -- 在转义后的大括号中加上一个数字, 这个数字就是它前面的RE所能匹配的次数.

    大括号必须经过转义, 否则, 大括号仅仅表示字面含意. 这种用法并不是基本RE集合中的一部分, 仅仅是个技巧而以.

    "[0-9]\{5\}" 精确匹配5个数字 (所匹配的字符范围是0到9).

    Note

    使用大括号形式的RE是不能够在"经典"(非POSIX兼容)的awk版本中正常运行的. 然而, gawk命令中有一个--re-interval选项, 使用这个选项就允许使用大括号形式的RE了(无需转义).

     

    bash$ echo 2222 | gawk --re-interval '/2{3}/'
    2222

    Perl与某些版本的egrep不需要转义大括号.

  • 圆括号 -- ( ) -- 括起一组正则表达式. 当你想使用expr进行子字符串提取(substring extraction)的时候, 圆括号就有用了. 如果和下面要讲的"|"操作符结合使用, 也非常有用.

  • 竖线 -- | -- 就是RE中的"或"操作符, 使用它能够匹配一组可选字符中的任意一个.

     

    bash$ egrep 're(a|e)d' misc.txt
    People who read seem to be better informed than those who do not.
    The clarinet produces sound by the vibration of its reed.

Note

与GNU工具一样, 某些版本的sed, ed, 和ex一样能够支持扩展正则表达式, 上边这部分就描述了扩展正则表达式.

  • POSIX字符类. [:class:]

    这是另外一种, 用于指定匹配字符范围的方法.

  • [:alnum:] 匹配字母和数字. 等价于A-Za-z0-9.

  • [:alpha:] 匹配字母. 等价于A-Za-z.

  • [:blank:] 匹配一个空格或是一个制表符(tab).

  • [:cntrl:] 匹配控制字符.

  • [:digit:] 匹配(十进制)数字. 等价于0-9.

  • [:graph:] (可打印的图形字符). 匹配ASCII码值范围在33 - 126之间的字符. 与下面所提到的[:print:]类似, 但是不包括空格字符(空格字符的ASCII码是32).

  • [:lower:] 匹配小写字母. 等价于a-z.

  • [:print:] (可打印的图形字符). 匹配ASCII码值范围在32 - 126之间的字符. 与上边的[:graph:]类似, 但是包含空格.

  • [:space:] 匹配空白字符(空格和水平制表符).

  • [:upper:] 匹配大写字母. 等价于A-Z.

  • [:xdigit:] 匹配16进制数字. 等价于0-9A-Fa-f.

    Important

    POSIX字符类通常都要用引号或双中括号([[ ]])引起来.

     

    bash$ grep [[:digit:]] test.file
    abc=723

    如果在一个受限的范围内, 这些字符类甚至可以用在通配(globbing)中.

     

    bash$ ls -l ?[[:digit:]][[:digit:]]?
    -rw-rw-r-- 1 bozo bozo 0 Aug 21 14:47 a33b

    如果想了解POSIX字符类在脚本中的使用情况, 请参考例子 12-18例子 12-19.

Sed, awk, 和Perl在脚本中一般都被用作过滤器, 这些过滤器将会以RE为参数, 对文件或者I/O流进行"过滤"或转换. 请参考例子 A-12例子 A-17, 来详细了解这种用法.

对于RE这个复杂的主题, 标准的参考材料是Friedl的Mastering Regular Expressions. 由Dougherty和Robbins所编写的Sed & Awk这本书, 也对RE进行了清晰的论述. 如果想获得这些书的更多信息, 请察看参考文献.

注意事项

[1]

因为sed, awk, 和grep通常用于处理单行, 但是不能匹配一个换行符. 如果你想处理多行输入的话, 那么你可以使用"点"来匹配换行符.

  1 #!/bin/bash

3 sed -e 'N;s/.*/[&]/' << EOF # Here Document
4 line1
5 line2
6 EOF
7 # 输出:
8 # [line1
9 # line2]
10 
11 
12 
13 echo
14 
15 awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' << EOF
16 line 1
17 line 2
18 EOF
19 # 输出:
20 # line
21 # 1
22 
23 
24 # 感谢, S.C.
25
26 exit 0