2. 基本語法

我們知道C的變數和Shell腳本變數的定義和使用方法很不相同,表達能力也不相同,C的變數有各種類型,而Shell腳本變數都是字元串。同樣道理,各種工具和編程語言所使用的正則表達式規範的語法並不相同,表達能力也各不相同,有的正則表達式規範引入很多擴展,能表達更複雜的模式,但各種正則表達式規範的基本概念都是相通的。本節介紹egrep(1)所使用的正則表達式,它大致上符合POSIX正則表達式規範,詳見regex(7)(看這個man page對你的英文絶對是很好的鍛鍊)。希望讀者仿照上一節的例子,一邊學習語法,一邊用egrep命令做實驗。

表 32.1. 字元類

字元含義舉例
.匹配任意一個字元abc.可以匹配abcdabc9
[]匹配括號中的任意一個字元[abc]d可以匹配adbdcd
-[]括號內表示字元範圍[0-9a-fA-F]可以匹配一位十六進制數字
^位於[]括號內的開頭,匹配除括號中的字元之外的任意一個字元[^xy]匹配除xy之外的任一字元,因此[^xy]1可以匹配a1b1但不匹配x1y1
[[:xxx:]]grep工具預定義的一些命名字元類[[:alpha:]]匹配一個字母,[[:digit:]]匹配一個數字

表 32.2. 數量限定符

字元含義舉例
?緊跟在它前面的單元應匹配零次或一次[0-9]?\.[0-9]匹配0.02.3.5等,由於.在正則表達式中是一個特殊字元,所以需要用\轉義一下,取字面值
+緊跟在它前面的單元應匹配一次或多次[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+匹配email地址
*緊跟在它前面的單元應匹配零次或多次[0-9][0-9]*匹配至少一位數字,等價于[0-9]+[a-zA-Z_]+[a-zA-Z_0-9]*匹配C語言的標識符
{N}緊跟在它前面的單元應精確匹配N次[1-9][0-9]{2}匹配從100999的整數
{N,}緊跟在它前面的單元應匹配至少N[1-9][0-9]{2,}匹配三位以上(含三位)的整數
{,M}緊跟在它前面的單元應匹配最多M[0-9]{,1}相當於[0-9]?
{N,M}緊跟在它前面的單元應匹配至少N次,最多M[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}匹配IP地址

再次注意grep找的是包含某一模式的行,而不是完全匹配某一模式的行。再舉個例子,如果文本檔案的內容是

aaabc
aad
efg

查找a*這個模式的結果是三行都被找出來了

$ egrep 'a*' testfile 
aabc
aad
efg

a*匹配0個或多個a,而第三行包含0個a,所以也包含了這一模式。單獨用a*這樣的正則表達式做查找沒什麼意義,一般是把a*作為正則表達式的一部分來用。

表 32.3. 位置限定符

字元含義舉例
^匹配行首的位置^Content匹配位於一行開頭的Content
$匹配行末的位置;$匹配位於一行結尾的;號,^$匹配空行
\<匹配單詞開頭的位置\<th匹配... this,但不匹配ethernettenth
\>匹配單詞結尾的位置p\>匹配leap ...,但不匹配parentsleepy
\b匹配單詞開頭或結尾的位置\bat\b匹配... at ...,但不匹配catatexitbatch
\B匹配非單詞開頭和結尾的位置\Bat\B匹配battery,但不匹配... attendhat ...

位置限定符可以幫助grep更準確地查找,例如上一節我們用[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}查找IP地址,找到這兩行

192.168.1.1
1234.234.04.5678

如果用^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$查找,就可以把1234.234.04.5678這一行過濾掉了。

表 32.4. 其它特殊字元

字元含義舉例
\轉義字元,普通字元轉義為特殊字元,特殊字元轉義為普通字元普通字元<寫成\<表示單詞開頭的位置,特殊字元.寫成\.以及\寫成\\就當作普通字元來匹配
()將正則表達式的一部分括起來組成一個單元,可以對整個單元使用數量限定符([0-9]{1,3}\.){3}[0-9]{1,3}匹配IP地址
|連接兩個子表達式,表示或的關係n(o|either)匹配noneither

以上介紹的是grep正則表達式的Extended規範,Basic規範也有這些語法,只是字元?+{}|()應解釋為普通字元,要表示上述特殊含義則需要加\轉義。如果用grep而不是egrep,並且不加-E參數,則應該遵照Basic規範來寫正則表達式。