1. 程式人生 > >關於linux下使用grep和egrep中單引號‘’、雙引號“”、小括號()和大括號{}的一些問題

關於linux下使用grep和egrep中單引號‘’、雙引號“”、小括號()和大括號{}的一些問題

最近在linux下使用grep和egrep發現了一些問題。以前一直以為egrep包含了grep,因此grep中採用的格式,在egrep中能得到相同的結果。其實這個想法是不對的。

原因主要是在於正則表示式和擴充套件正則表示式的一些元符號上的問題,在這篇帖子(http://www.linuxidc.com/Linux/2014-03/99152.htm)中我找到了答案:

BRE與ERE在能力上區別僅在多項匹配的能力上,其他方面沒有大的差別,主要的區別體現在元字元上。

BRE只定義了4組元字元:

[]      用於在多個字元中選定一個字元進行匹配,[]內可以有-以示範圍,但-本身不是元字元

.        用於匹配任意字元

^      用於匹配時表示“非”的含義,還有一個用法是匹配行首

$      用於匹配行尾

ERE在此基礎上增加了3組元字元的定義:

{}      用於表示重複匹配的次數。BRE中只將{}當作普通字元對待,要使用此功能必須加\進行轉義,即“\{\}”

()      用於分組。BRE中只將()當作普通字元對待,要使用此功能必須加\進行轉義,即“\(\)”

|      完全為ERE新增的多項匹配能力定義的,BRE無多項匹配能力,只將|作普通字元對待


在這裡我插一句:我最開始看正則表示式,是鳥哥的linux私房菜基礎篇第三版上講正則的那一塊兒。後面發現問題再回去看,發現有個地方寫的不清楚,導致我很多試驗結果不太對。後來看到上面部落格中寫的,我才明白。鳥哥這裡寫的可能表述有點小問題。裡面在介紹BRE中採用大括號表示匹配次數中,如下圖中例題五那兒加粗的解釋:

然而,因為是BRE,因此必須採用\{ \} ,而不是{}。這並不是因為shell中對{}有特殊含義,才使用的轉義\。因為鳥哥在寫的時候已經加上單引號''了,shell不會再對單引號裡面的進行轉義了。(但是如果不加引號,確實需要再轉義,此時應該寫成\\\{ 和\\\},前面一對\\是產生\,後面一對\{是產生{)因此,在linux下還有可能受到‘’和“”

的影響,因此,在linux下采用grep或者egrep時,應該注意:

1、當pattern或者說匹配模式中,沒有空格,可以不用引號,但是有空格一定要用引號。

2、考慮單引號和雙引號的區別,考慮pattern是否有變數,是否需要求值

3、採用的是BRE還是ERE(這在採用小括號()和大括號{}的時候非常重要)

我們看幾個例子:

測試文字是demo.txt

裡面內容是:

This
Thi
This Thi
aaThiaa
(a)
a{10}
abcedefghi

一、找出一個由三個字母構成的單詞,該單詞由Th開頭

當然我們可以這樣寫

grep -n '\bTh.\b' demo.txt


現在我們換個思路,一個單詞,前面除非為一行開頭或者空格,後面為行結尾或者空格,那麼我們可以這麼寫:

grep -nE '(^|[[:space:]])Th.($|[[:space:]])' demo.txt 
或者 
egrep -n '(^|[[:space:]])Th.($|[[:space:]])' demo.txt  
這裡一定要用ERE,因為有 | 這個元符號

結果如下:


二、找到由十個字母構成的單詞,這裡不考慮一種關於單詞的限定,我們只要區別於demo.txt中後面的兩行

如果我們用grep

應該寫成:

 grep -n '[a-z]\{10\}' demo.txt 
結果如下:

如果寫成:

grep -n '[a-z]{10}' demo.txt 
結果如下:

因此,在BRE中,大括號{}預設就是本身,如果需要使用表示匹配字元的格式,應該用\{ \}

如果,我們在linux shell中,寫grep時不用單引號,應該這麼寫:

grep -n [a-z]\\\{10\\\} demo.txt


這是因為shell先把命令讀進去,然後把 \\ 變成 \,把 \{ 變成{, 所以才能形成\{。因此在引號裡面寫成\{並不是shell的原因,是BRE本身的語法規則,如果不加引號,才需要考慮shell可能有一些特殊字元需要轉義。如果要匹配第6行,就要寫成:
grep -n [a-z]\{10\} demo.txt


所以,我覺得,在linux shell 中使用grep 時 pattern部分加上引號更加方便。

如果我們使用egrep

 egrep -n '[a-z]{10}' demo.txt 


因為此時是ERE,語法上就是直接使用{},如果要匹配第6行,應該是
egrep -n '[a-z]\{10\}' demo.txt


如果不加引號,應該這麼寫:

egrep -n [a-z]\{10\} demo.txt 


如果不加引號,要匹配第6行,應該是

 egrep -n [a-z]\\\{10\\\} demo.txt 



我們可以看出,在上面grep和egrep中的例子中,結果正好是對調的,這主要是因為BRE和ERE語法中元符號的形式的原因,因此egrep和grep在寫的時候一定考慮好模式的表達。

除此以外,還要注意linux shell中單引號‘’ 和雙引號“”的區別。