Linux之正則表達式---grep、元字符、任意字符、錨、中括號、否定、POSIX字符類

正則表達式是一個非常重要的用於文本操作的工具。

0.參考文獻

《Linux命令行大全》 [美] William E. Shotts. Jr 著 郭光偉 郝記生 譯, 人民郵電出版社

更多有用的Linux知識詳解,可參加博主的Linux學習導航頁

1.什麼是正則表達式

正則表達式是一種符號表示法,用於識別文本模式。在某種程度上,它們類似於匹配文件和路徑名使用的shell通配符
許多命令行工具和大多數編程語言都支持正則表達式,以此來解決文本操作方面的問題。但不同的編程語言之間,正則表達式會略有不同。
方便起見,我們將正則表達式的討論限定在POSIX標準中。

2. grep–文本搜索

處理正則表達式的主要程序是grep。grep程序名字源於"global regular expression print"。實際上,grep搜索文本中與指定正則表達式匹配的行,並將結果送至標準輸出。
grep程序的語法爲

grep [options] regex [file ...]

表1 grep常用的選項

選項 功能描述
-i 忽略大小寫。也可以用–ignore-case指定
-v 不匹配。正常情況下,grep會輸出匹配行,而該選項可使grep輸出不包含匹配項的所有行,也可以用–invert-match指定。
-c 輸出匹配項數目(如果有-v選項,就輸出不匹配項的數目)而不是直接輸出匹配行自身,也可使用–count指定
-l 輸出匹配項文件名而不是直接輸出匹配行自身。也可以用–files-with-matches指定
-L 與-l選項類似,但輸出的是不含匹配項的文件名,可以用–files-without-match指定
-n 在每個匹配行前面加上該行在文件內的行號。也可以用–line-number指定
-h 進行多文件搜索時,抑制文件名輸出。也可用–no-filename指定

我們創建幾個示例文件來進行搜索

$ ls /bin > dirlist-bin.txt
$ ls /usr/bin > dirlist-usr-bin.txt
$ ls /sbin/ > dirlist-sbin.txt
$ ls /usr/sbin > dirlist-usr-sbin.txt
$ ls dirlist*.txt
dirlist-bin.txt  dirlist-sbin.txt  dirlist-usr-bin.txt  dirlist-usr-sbin.txt

我們可以對文件列表執行簡單的搜索

$ grep bzip dirlist*.txt
dirlist-bin.txt:bzip2
dirlist-bin.txt:bzip2recover

上個例子中,grep命令會搜索所有的文件,以查找字符串bzip,並找到了兩個匹配項,並且這兩個匹配項都在文件dirlist-bin.txt中。
如果我們只對包含匹配項的文件感興趣而不是對匹配項本身感興趣,可以指定-l選項。

$ grep -l bzip dirlist*.txt
dirlist-bin.txt

相反,如果只想查看那些不包含匹配項的文件,則可以用如下命令行

$ grep -L bzip dirlist*.txt
dirlist-sbin.txt
dirlist-usr-bin.txt
dirlist-usr-sbin.txt

3.元字符和文字

字符串bzip中的字符都是文字字符(literal character),即它們只能與自身進行匹配。除了文字字符,正則表達式還可以包含用於指定更爲複雜的匹配的元字符。正則表達式的元字符包含以下字符

^ $ . [ ] { } - ? * + ( ) | \

4.任意字符

接下來要討論的第一個元字符是**“點”字符或者句點字符。該字符用於匹配任意字符**。

$ grep -h '.zip' dirlist*.txt
bunzip2
bzip2
bzip2recover
gunzip
gzip
funzip
gpg-zip
unzip
unzipsfx

上述命令行,搜索到所有匹配正則表達式.zip的命令行。但其輸出中沒有包含zip程序,這是因爲正則表達式中的“.”元字符將匹配長度增加到了4個字符。而“zip”只包含3個字符。此時,文件擴展名中的“.”符號也被當做**“任意字符”**處理了。

5.錨

插入符(^)和美元符號($)在正則表達式中被當做,也就是說正則表達式只與行的開頭(^)或是末尾($)的內容進行匹配比較

$ grep -h '^zip' dirlist*.txt
zipdetails
zipgrep
zipinfo
$ grep -h 'zip$' dirlist*.txt
gunzip
gzip
funzip
gpg-zip
unzip
$ grep -h '^zip$' dirlist*.txt
zip

6.中括號表達式和字符類

中括號除了可以用於匹配正則表達式中給定位置的任意字符外,還可以用於匹配指定字符集的單個字符
如下命令行則利用一個兩個字母組成的字符集,用於匹配包含bzip和gzip字符串的文本行。

$ grep -h '[bg]zip' dirlist*.txt
bzip2
bzip2recover
gzip

一個字符集可以包含任意數目的字符,並且當元字符放置到中括號時,會失去它們的特殊意義
兩種情況下,在中括號中使用元字符,會有不同的意義。第一個是插入符(^),其在中括號中表示否定。另外一個是連字符(-),它表示字符範圍。

6.1 否定

如果中括號內的第一個字符是插入符(^),那麼剩下的字符則被當做不應該在指定位置出現的字符集。

$ grep -h '[^bg]zip' dirlist*.txt
bunzip2
gunzip
funzip
gpg-zip
unzip
unzipsfx

以上例子通過否定操作,得到那些包含zip字符串但zip前面既不是b也不是g的所有程序。注意,此時zip仍沒有出現在結果列表中,可見否定時,字符集仍然需要在指定位置有對應字符。
只有在插入字符(^)在中括號表達式中第一個字符時纔會被當做否定符。如果不是,則被轉義爲普通字符。

6.2 傳統字符範圍

如果我們希望查找文件名義大寫字母開頭的文件,可以用以下簡單方法:

$ grep -h '^[A-Z]' dirlist*.txt
MAKEDEV
ControlPanel
Mail
NF
VGAuthService
X
X11
Xorg

再例如,下面例子可以匹配以字母和數字開頭的所有文件名

$ grep -h '^[A-Za-z0-9]' dirlist*.txt

如果我們真要查找含有連字符“-”的文件,可以在中括號中第一個字符使用連字符

$ grep -h '[-AZ]' dirlist*.txt

6.3 POSIX字符類

表2 POSIX字符類

字符類 描述
[:alnum:] 字母字符和數字字符;在ASCII碼中,與[A-Za-z0-9]等效
[:word:] 基本與[:alnum:]一樣,只是多了個下劃線字符(_)
[:alpha:] 字母字符
[:blank:] 包括空格和製表符
[:cntrl:] ASCII控制碼;包含ASCII字符0~31以及127
[:digit:] 數字0~9
[:graph:] 可見字符;在ASCII中,包含字符33~126
[:lower:] 小寫字母
[:punct:] 標點符號字符
[:print:] 可打印字符;包括[:graph:]中所有字符再加上空格字符
[:space:] 空白字符如空格符、製表符、回車符、換行符、垂直製表符以及換頁符
[:upper:] 大寫字母
[:xdigit:] 用於表示十六進制的字符

7. POSIX基本正則表達式和擴展正則表達式

POSIX規範將正則表達式分爲兩種:基本正則表達式(BRE)擴展正則表達式(ERE)
BRE和ERE的不同僅僅在於元字符的不同。在BRE方式中,只承認^、$、.、[、]、*這些元字符,所有的其它字符都被識別爲文字字符。而ERE中,則添加了(、)、{、}、?、+、|等元字符。
由於下面要討論的特性是ERE的一部分,所以需要使用不一樣的grep。一般是執行egrep程序,但是GNU版本的grep可以運行-E選項以支持ERE方式。

8.或選項

括號表達式可以從指定字符集中匹配單一字符,而或選項則用於從字符集或正則表達式集中尋找匹配項

x$ echo "AAA" | grep AAA
AAA
$ echo "AAA" | grep BBB
$ echo "AAA" | grep -E 'AAA|BBB'
AAA

這裏出現了’AAA|BBB’正則表達式,含義是“匹配字符串AAA或者字符串BBB”。
注意,此時使用擴展選項,因此需要爲grep增加-E選項,並且將正則表達式引起來防止shell將元字符“|”當做管道處理。
另外,或選項不侷限於兩種,例如

$ echo "AAA" | grep -E 'AAA|BBB|CCC'
AAA

爲了將或選項與其它正則表達式符號結合使用,可以用“()”將或選項的所有元素與其它符號隔開。

$ grep -Eh '^(bz|gz|zip)' dirlist*.txt

以上表達式的含義是匹配文件名義bz、gz或是zip開頭的文件。如果不含有括號

$ grep -Eh '^bz|gz|zip' dirlist*.txt

含義就變成了以bz開頭或者是包含gz和zip的文件。

9.限定符

擴展正則表達式(ERE)提供多種方法指定某元素匹配的次數

9.1 ?—匹配某元素0次或1次

該限定符實際上意味着“前面的元素可選”。
例如檢查某電話號的有效性,必須是下面格式(nnn) nnn-nnnn和nnn nnn-nnnn中的一種,其中n是數值。
可以構造下面的正則表達式:
^(?[0-9][0-9][0-9])? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$
表示括號字符只能匹配一次或零次。反斜槓告訴shell括號已經轉義。

$ echo "(555) 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
(555) 123-4567
$ echo "555 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
555 123-4567
$ echo "AAA 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'

9.2 *—匹配某元素多次或零次

與“?”元字符類似,“*”用於表示一個可選擇的條目。然而,與“?”不同,該條目可以出現多次,而不僅僅是一次。
例如,我們想知道一串字符是否以大寫字母開頭而以句號結束,並且中間內容是任意數目的大小寫字母和空格。那麼可以使用如下正則表達式。
[[:upper:]][[:upper:][:lower:] ]*.
以上表達式包含了三個條目:包含[:upper:]字符類的中括號表達式、包含[:upper:]和[:lower:]兩個字符類以及一個空格的空括號表達式、用反斜槓轉義過的圓點字符。第二個條目中緊跟“*”元字符,所以只要句子的第一個字母是大寫字母,後面不管會出現多少數目的大小寫字母都無關緊要。

$ echo "This works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This works.
$ echo "This Works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This Works.
$ echo "this does not" | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'

9.3 ±–匹配某元素一次或多次

'+‘元字符與’*‘非常類似,只是’+'要求置於其前面的元素至少出現一次
示例如下,該正則表達式用於匹配由單個空格分隔的一個或者多個字母字符組成的行。
^([[:alpha:]]+ ?)+$

$ echo "This that" | grep -E '^([[:alpha:]]+ ?)+$'
This that
$ echo "a b c" | grep -E '^([[:alpha:]]+ ?)+$'
a b c
$ echo "a b 9" | grep -E '^([[:alpha:]]+ ?)+$'

$echo "a b  d" | grep -E '^([[:alpha:]]+ ?)+$'

9.4 {}—以指定次數匹配某元素

“{”和“}”元字符用於描述最小和最大匹配次數的需求。有四種方法
表3 指定匹配次數

指定項 含義
{n} 前面的元素恰好出現n次則匹配
{n,m} 前面的元素出現次數在n~m次之間時則匹配
{n,} 前面的元素出現次數超過n次則匹配
{,m} 前面的元素出現次數不超過m次則匹配

例如前面電話號碼可以改爲
“^(?[0-9]{3})? [0-9]{3}-[0-9]{4}$”

10.正則表達式的應用

10.1 使用grep

以上已經展示很多了

10.2 用find查找文件名

find命令的test選項可以用正則表達式表示,與grep有所不同,grep命令是搜索那些只包含與指定表達式匹配的字符串的行,而find則要求文件名與指定表達式完全一致
例如

$ find . -regex '.*[^-_-./0-9a-zA-Z].*'

10.3 用locate查找文件

locate命令既支持基本正則表達式(–regexp)選項,也支持擴展正則表達式(–regex選項)。利用locate,可以完成之前對dirlist文件所做的許多操作。

$  locate --regex 'bin/(z|gz|zip)'

10.4 利用less和vim命令搜索文本

less和vim採用同樣的方式進行文本搜索。按下“/”鍵後輸入正則表達式,即開始進行搜索。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章