以前我们用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
查找一个模式,如何表示这个模式,这一类字符串,而不是一个特定的字符串呢?从这两个简单的例子可以看出,要表示一个模式至少应该包含以下信息:
规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符一起表示一个模式,这就是正则表达式(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.5678
egrep
相当于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等等。“正则表达式”就像“变量”一样,它是一个广泛的概念,而不是某一种工具或编程语言的特性。