shell教程
OutOfMemory.CN技术专栏-> shell-> shell教程-> 第19章. 正则表达式

第19章. 正则表达式

为了充分发挥shell编程的威力,你需要精通正则表达式。在脚本编程中的一些命令和软件包普遍使用正则表达式,例如grep,expr,sed和awk.一个正式表达式是一个字符串.字符串里的字符被称为元字符,它们可以表示了比它们字面上看起来的意思更丰富的含义。例如,一个引用符号可以表示引用一个人演讲中的话,或者表示下面将要讲到的引申表示的意思。正则表达式是一个字符或/和元字符组合成的字符集,它们匹配(或

为了充分发挥shell编程的威力,你需要精通正则表达式。 在脚本编程中的一些命令和软件包普遍使用正则表达式,例如grep, expr, sedawk.

一个正式表达式是一个字符串.字符串里的字符被称为元字符,它们可以表示了比它们字面上看起来的意思更丰富的含义。例如,一个引用符号可以表示引用一个人演讲中的话,或者表示下面将要讲到的引申表示的意思。正则表达式是一个字符或/和元字符组合成的字符集,它们匹配(或指定)一个模式。.

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

  • 一个字符集. 这里的字符集里的字符表示的就是它们字面上的意思.正则表达式最简单的情况就是仅仅由字符集组成,而没有其他的元字符.

  • . 一个锚指明了正则表达式在一行文本中要匹配的位置,例如^$就是锚.

  • 修饰符. 它们用于展开或缩小(即是修改了)正则表达式匹配文本行的范围.修饰符包括了星号,括号和反斜杠符号.

正则表达是的主要作用是用来文本搜索和字串操作。一个正则表达式匹配一个字符或是一串字符--完整的一串字符或是另外一个字符串的子串.

  • 星号 -- * -- 匹配前一个字符的任意多次(包括零次)。

    "1133*"匹配11 + 一个或更多的3 + 可能的其他字符: 113, 1133, 111312, 等等.

  • 点 -- . -- 匹配除了新行符之外的任意一个字符. [1]

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

  • 脱字符 -- ^ -- 匹配一行的开头,但依赖于上下文环境,可能在正则表达式中表示否定一个字符集的意思.

  • 美元符 -- $ -- 在正则表达式中匹配行尾.

    "^$" 匹配空行.

  • 方括号 -- [...] -- 在正则表达式中表示匹配括号中的一个字符.

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

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

    "[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).

  • 反斜杠字符 -- \ -- 转义(escapes) 一个特殊的字符,使这个字符表示原来字面上的意思.

    "\$"表示了原来的字面意思"$",而不是在正则表达式中表达的匹配行尾的意思.同样,"\\"也被解释成了字面上的意思"\".

  • 转义(escape)"尖角号" -- \<...\> -- 用于表示单词的边界.

    尖角号必须被转义,因为不这样做的话它们就表示单纯的字面意思而已.

    "\<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中使用.

  • 问号 -- ? -- 匹配零或一个前面的字符. 它一般用于匹配单个字符.

  • 加号 -- + -- 匹配一个或多个前面的字符.它的作用和*很相似,但唯一的区别是它不匹配零个字符的情况.

    # GNU 版本的 sed 和 awk 可以使用"+",
    # 但它应该转义一下.
    
    echo a111b | sed -ne '/a1\+b/p'
    echo a111b | grep 'a1\+b'
    echo a111b | gawk '/a1+b/'
    # 上面三句都是等价的效果.
    
    # 多谢, S.C.

  • 转义"大括号" -- \{ \} -- 指示前面正则表达式匹配的次数.

    要转义是因为不转义的话大括号只是表示他们字面上的意思。这个用法只是技巧上的而不是基本正则表达式的内容。

    "[0-9]\{5\}" 精确匹配5个数字 (从 0 到 9的数字).

    大括号不能在“经典”(不是POSIX兼容)的正则表达式版本的awk中使用. 然而, gawk一个选项--re-interval来允许使用大括号(不必转义).

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

    Perl和一些egrep版本不要求转义大括号.

  • 圆括号 -- ( ) -- 括起一组正则表达式. 它和下面要讲的"|"操作符或在用expr进行子字符串提取(substring extraction)一起使用很有用。

  • 竖线 -- | -- "或"正则操作符用于匹配一组可选的字符.

     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.
     	      

一些sed, ed, 和ex的版本像GNU的软件版本一样支持上面描述的扩展正则表达式的版本。

  • POSIX字符类. [:class:]

    这是另外一个可选的用于指定匹配字符范围的方法。

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

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

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

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

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

  • [:graph:] (可打印的图形字符). 匹配 ASCII 码值的33 - 126之间的字符. 这和下面提到的 [:print:]一样,但是不包括空格字符.

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

  • [:print:] (可打印字符). 匹配 ASCII码值 32 - 126之间的字符. 这和上面提到的一样[:graph:],但是增多一个空格字符。

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

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

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

    POSIX字符类一般都要求用引号或是双方括号double brackets ([[ ]])引起来.

     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在脚本中被用作过滤器, "过滤"或转换文件/IO流的时候以正则表达式作为参数。参考例子 A-12例子 A-17 来理解这种用法.

在正则表达式这个复杂主题的标准参考是Friedl的Mastering Regular Expressions.由Dougherty和Robbins写的 Sed & Awk也给出了一个清晰的正则表达式论述. 查看参考书目 找到这个主题更多的信息.

[1]

因为Since sed, awk, 和and grep 通常处理单行,而不能匹配一个新行符. 在要处理多行的一个输入时,可以使用点操作符,它可以匹配新行符。

#!/bin/bash

sed -e 'N;s/.*/[&]/' << EOF   # Here Document
line1
line2
EOF
# 输出:
# [line1
# line2]



echo

awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' << EOF
line 1
line 2
EOF
# 输出:
# line
# 1


# 多谢, S.C.

exit 0

© 内存溢出 OutOfMemory.CN