1. 引言

以前我們用grep在一個檔案中找出包含某些字元串的行,比如在標頭檔中找出一個宏定義。其實grep還可以找出符合某個模式(Pattern)的一類字元串。例如找出所有符合xxxxx@xxxx.xxx模式的字元串(也就是email地址),要求x字元可以是字母、數字、下劃線、小數點或減號,email地址的每一部分可以有一個或多個x字元,例如abc.d@ef.com1_2@987-6.54,當然符合這個模式的不全是合法的email地址,但至少可以做一次初步篩選,篩掉a.bc@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等等。“正則表達式”就像“變數”一樣,它是一個廣泛的概念,而不是某一種工具或編程語言的特性。