上回說到grep與正則表達(dá)式關(guān)系緊密,今天來詳細(xì)的談一談。
1. 簡介
正則表達(dá)式,讓人不明覺厲,望而卻步。但實(shí)際上它就相當(dāng)于數(shù)學(xué)里的九九乘法表,背會很難,之后做乘法就很快了。
正則表達(dá)式也是這樣的工具,看起來很難,背會了之后大有幫助。乘法表建立了乘法的基礎(chǔ)規(guī)則,而正則表達(dá)式建立了一系列語法的規(guī)則。它是用來匹配符合某種語法的字符串,從而可以對這些篩選出來的字符串進(jìn)行處理。
所以天然的,在Linux中,grep命令經(jīng)常與正則表達(dá)式結(jié)合起來執(zhí)行一些模糊查詢或者指向性查詢。
比如一些常見的:
ll | grep -E "*.txt"
#列出當(dāng)前路徑下的txt文件
#-E選項(xiàng)表示使用擴(kuò)展的正則表達(dá)式,grep -E相當(dāng)于egrep
#"*"就是一種正則表達(dá)式的元字符
【注】其實(shí)直接使用ll *.txt
也能得到相同結(jié)果,這是因?yàn)長inux直接把*解釋為任意的字符串。
二、正則表達(dá)式基礎(chǔ)
正則表達(dá)式是如何建立語法規(guī)則的呢?它定義了一系列的元字符(像"*"這樣的),通過元字符和其他字符的組合來表達(dá)出一種規(guī)則,對待匹配文本進(jìn)行篩選,只有符合這種規(guī)則的文本才能被保留下來。
- 基本正則表達(dá)式所定義的元字符
元字符 | 作用 | 例子 | 例子說明 |
---|---|---|---|
^ | 行首定位符 | ^ty | 匹配"t"開頭,后面緊跟一個"y"的字符串 |
$ | 行尾定位符 | txt$ | 匹配以"t"結(jié)尾,前面兩個字符是"t""x"的字符串 |
. | 單個字符匹配 | s. | 匹配"s"后面有一個字符的字符串 |
* | 限定符 | s* | "*"表示匹配其前導(dǎo)字符若干次,包括0次。這里是匹配有若干個"s"的字符串 |
[] | 字符集匹配 | [abc] | 表示匹配"a","b"或"c"的字符串 |
[^] | 字符集不匹配 | [^abc | 表示不匹配"a","b","c"里的任意字符 |
() | 子表達(dá)式 | ([0-9]{2})? | 匹配兩個或0個數(shù)字 |
x{m,n} | 區(qū)間表達(dá)式 | a{2,3} | 表示"a"重復(fù)2~3次 |
- 擴(kuò)展正則表達(dá)式的元字符
元字符 | 作用 | 例子 | 例子說明 |
---|---|---|---|
+ | 限定符,同* | s+ | "+"表示匹配其前導(dǎo)字符若干次,至少1次 |
? | 限定符 | ss? | "?"表示前面的字符可以重復(fù)0或1次。這里是一個"s"后面可能再跟一個"s" |
- POSIX字符集
不同國家的字符編碼很有可能不同,例如:
LANG=C:A B C D ... Z a b c d ...z
LANG=zh_TW:a A b B c C d D ... z Z
當(dāng)采用第二種編碼時,[A-Z]之間會包括小寫字母b-z。所以為了避免這種問題,可以使用POSIX字符集來使用特定的字符類。
字符類 | 說明 |
---|---|
[:alnum:] | 匹配任意一個字母或者數(shù)字,等價于A-Za-z0-9 |
[:alpha:] | 匹配任意一個字母,等價于A-Za-z |
[:digit:] | 匹配任意一個數(shù)字,等價于0-9 |
[:lower:] | 匹配小寫字母,等價于a-z |
[:upper:] | 匹配大寫字母,等價于A-Z |
[:graph:] | 匹配一個看的見的字符,不包括空白字符 |
[:print:] | 匹配一個可以打印的字符 |
[:blank:] | 匹配空格和tab |
[:space:] | 匹配一個空白字符,包括空格、tab、換行、分頁符< |
[:punct:] | 匹配一個標(biāo)點(diǎn)符號 |
[:xdigit:] | 匹配一個十六進(jìn)制數(shù)字,即0-9,a-f,A-F |
【注意】這些字符類要放在方括號中,才能表示字符集匹配:[[:alnum:]] = [A-Za-z0-9]
三、grep與正則表達(dá)式的例子
(1)簡單匹配
#匹配空行
egrep "^$" testfile
#匹配所有英文字符
egrep "[a-zA-Z]" testfile
#匹配tast或者test
egrep "t[ae]st" testfile
#匹配以字符s開頭,緊跟若干b的文件名
ll | egrep "^sb*"
#匹配txt文件
ll | egrep "\.txt$" #這里的"."需要進(jìn)行轉(zhuǎn)義
(2)復(fù)雜一些的匹配
#匹配QQ號碼,第一位不能是0,5位以上的數(shù)字。
egrep "[1-9][0-9]{4,}" testfile
#匹配IP地址,共4組數(shù)字,用"."隔開
egrep "^([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\. #第一組數(shù)字
([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\. #第二組數(shù)字
([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\. #第三組數(shù)字
([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" #第四組數(shù)字
testfile
#匹配郵箱地址
egrep "^[a-z0-9]([a-z0-9]*[-_]?[a-z0-9]+)*@
([a-z0-9]*[-_]?[a-z0-9]+)+[.][a-z]{2,3}([.][a-z]{2})?$"
此處注意:區(qū)間表達(dá)式{}應(yīng)該寫成"\{\}"表示轉(zhuǎn)義,實(shí)驗(yàn)中發(fā)現(xiàn)加不加"\"轉(zhuǎn)義都能得出正確結(jié)果,但是直接使用基本正則表達(dá)式(grep不加-E選項(xiàng))則不行。所以應(yīng)該是擴(kuò)展正則表達(dá)式中取消了這個需要轉(zhuǎn)義字符的地方。
四、其他
瑣碎的片段:
當(dāng)需要將元字符當(dāng)作普通字符匹配的時候,需要轉(zhuǎn)移字符"\",但是當(dāng)元字符位于"[]"中時,除了"-"或者"^"極少數(shù)元字符以外,其它的自動轉(zhuǎn)義為普通字符。
正則表達(dá)式從左到右計算,遵循一定的優(yōu)先級:轉(zhuǎn)義符"\" > 方括號"[]" > 分組 "()" > 限定符"*,+,?,{}" > 普通字符 > 定位符"^,$" > 或"|"。
匹配同一種字符可能有多種正則表達(dá)式的寫法。
shell本身不支持正則表達(dá)式,但是支持"*","?"等通配符。
支持正則表達(dá)式的還有sed命令,awk命令。以后可以詳述。
參考:
shell從入門到精通,張春曉等編著;
鳥哥的Linux私房菜。