1. 引言
以前我们用 grep 在一个文件中找出包含某些字符串的行,比如在头文件中找出一个宏定义。其实 grep 还可以找出符合某个模式(Pattern)的一类字符串。例如找出所有符合 xxxxx@xxxx.xxx 模式的字符串(也就是 email 地址),要求 x 字符可以是字母、数字、下划线、小数点或减号,email 地址的每一部分可以有一个或多个 x 字符,例如 abc.d@ef.com 、 1_2@987-6.54 ,当然符合这个模式的不全是合法的 email 地址,但至少可以做一次初步筛选,筛掉 a.b 、 c@d 等肯定不是 email 地址的字符串。再比如,找出所有符合 yyy.yyy.yyy.yyy 模式的字符串(也就是 IP 地址),要求 y 是 0-9 的数字,IP 地址的每一部分可以有 1-3 个 y 字符。
如果要用 grep 查找一个模式,如何表示这个模式,这一类字符串,而不是一个特定的字符串呢?从这两个简单的例子可以看出,要表示一个模式至少应该包含以下信息:
- 字符类(Character Class):如上例的 x 和 y,它们在模式中表示一个字符,但是取值范围是一类字符中的任意一个。
- 数量限定符(Quantifier):邮件地址的每一部分可以有一个或多个 x 字符,IP 地址的每一部分可以有 1-3 个 y 字符
- 各种字符类以及普通字符之间的位置关系:例如邮件地址分三部分,用普通字符
@和.隔开,IP 地址分四部分,用.隔开,每一部分都可以用字符类和数量限定符描述。为了表示位置关系,还有位置限定符(Anchor)的概念,将在下面介绍。
规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符一起表示一个模式,这就是正则表达式(Regular Expression)。例如 email 地址的正则表达式可以写成 [a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+ ,IP 地址的正则表达式可以写成 [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} 。下一节介绍正则表达式的语法,我们先看看正则表达式在 grep 中怎么用。例如有这样一个文本文件 testfile :
192.168.1.1
1234.234.04.5678
123.4234.045.678
abcde查找其中包含 IP 地址的行:
$ egrep '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' testfile
192.168.1.1
1234.234.04.5678egrep 相当于 grep -E ,表示采用 Extended 正则表达式语法。 grep 的正则表达式有 Basic 和 Extended 两种规范,它们之间的区别下一节再解释。另外还有 fgrep 命令,相当于 grep -F ,表示只搜索固定字符串而不搜索正则表达式模式,不会按正则表达式的语法解释后面的参数。
注意正则表达式参数用单引号括起来了,因为正则表达式中用到的很多特殊字符在 Shell 中也有特殊含义(例如 \),只有用单引号括起来才能保证这些字符原封不动地传给 grep 命令,而不会被 Shell 解释掉。
192.168.1.1 符合上述模式,由三个 . 隔开的四段组成,每段都是 1 到 3 个数字,所以这一行被找出来了,可为什么 1234.234.04.5678 也被找出来了呢?因为 grep 找的是包含某一模式的行,这一行包含一个符合模式的字符串 234.234.04.567 。相反, 123.4234.045.678 这一行不包含符合模式的字符串,所以不会被找出来。
grep 是一种查找过滤工具,正则表达式在 grep 中用来查找符合模式的字符串。其实正则表达式还有一个重要的应用是验证用户输入是否合法,例如用户通过网页表单提交自己的 email 地址,就需要用程序验证一下是不是合法的 email 地址,这个工作可以在网页的 Javascript 中做,也可以在网站后台的程序中做,例如 PHP、Perl、Python、Ruby、Java 或 C,所有这些语言都支持正则表达式,可以说,目前不支持正则表达式的编程语言实在很少见。除了编程语言之外,很多 UNIX 命令和工具也都支持正则表达式,例如 grep、vi、sed、awk、emacs 等等。“正则表达式”就像“变量”一样,它是一个广泛的概念,而不是某一种工具或编程语言的特性。