1、概念:
正則表達式(或稱Regular Expression,簡稱RE),是用於描述字符排列和匹配模式的一種語法規則。它主要用於字符串的分割,匹配、査找及替換操作。即正則表達式是一種文本模式,該模式描述在搜索文本時要匹配的一個或多個字符串。
這種枯燥的概念難理解,其實,正則表達式是用來匹配文件中的字符串的方法。它會先把整個文本分成一行一行的字符串,然后從每行字符串中搜索是否有符合正則表達式規則的字符串,如果有則匹配成功,如果沒有則匹配失敗。
注:正則表達式和通配符的區別(正則表達式用來在文件中匹配符合條件的字符串,通配符用來匹配符合條件的文件名)。其實這種區別只在 Shell 中適用,因為用來在文件中搜索字符串的命令,如 grep、awk、sed、vi 等可以支持正則表達式,而在系統中搜索文件的命令,如 ls、find、cp 等不支持正則表達式,所以只能使用 Shell 自己的通配符來進行匹配了。
在正則表達式中,我們把用於匹配的特殊符號又稱作元字符。在shell中,元字符又分為基礎元字符(BRE)和擴展元字符(ERE)。
基礎元字符 |
|
元字符 |
作 用 |
* |
匹配前面的一個字符或子表達式0次或任意多次。如:a*hello匹配所有0個或多個a后,緊跟hello的行。即hello前面可以有任意多個a。 |
. |
匹配除換行符和回車符(“\n”和"\r")外的任意一個字符。例如:l..e匹配包含一個l,后跟兩個任意字符,然后跟一個e的行。 |
.* |
表示匹配任意長度字符串 |
^ |
匹配行首。例如,^hello 會匹配以 hello 開頭的行。 |
$ |
匹配行尾。例如,hello$ 會匹配以 hello 結尾的行 |
^$ |
匹配空行 |
[] |
匹配中括號中指定的任意一個字符,而且只匹配一個字符。例如[aoeiu]匹配任意一個元音字母, [0-9] 匹配任意一位數字,[a-z][0-9] 匹配由小寫字母和一位數字構成的兩位字符,[a-zA-Z] 匹配任意一位英文字母 |
[^] |
匹配除中括號中的字符以外的任意一個字符。例如,[^0-9] 匹配任意一位非數字字符,[^a-z] 匹配任意一位非小寫字母, 注意:可以用^標記做[]內的前綴,表示除[]內的字符以外的任意一個字符。比如:搜索oo前沒有g的字符串的行,應用 '[^g]oo' 作搜索字符串。^符號如果出現在[]的起始位置表示否定,但是在[]的其他位置是普通字符。[^ab^c] 匹配除了a、b、^、c以外的任意單個字符。 |
\ |
轉義符,用於取消特殊符號的含義,使該特殊字符成為普通字符。例如:^\.[0-9][0-9]表示匹配以一個句點和兩個數字開始。 |
\{n\} |
表示其前面的字符出現 n 次。例如,[0-9]\{4\} 匹配4位數字,[1][3-8][0-9]\{9\} 匹配手機號碼。 |
\{n,\} |
表示其前面的字符出現不少於 n 次。例如,[0-9]\{2,\} 匹配兩位及以上的數字 |
\{n,m\} |
表示其前面的字符至少出現 n 次,最多出現 m 次。例如,[a-z]\{6,8\} 匹配 6〜8 位的小寫字母 |
\< \> |
匹配詞(word)的開始(\<)和結束(\>)。例如正則表達式\<the\>能夠匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:這個元字符不是所有的軟件都支持的。 |
擴展正則表達式
熟悉正則表達式的人應該很疑惑,在正則表達式中應該還可以支持一些元字符,比如"+"、"?"、"|"、"()"。
其實 Linux 是支持這些元字符的,只是 grep 命令默認不支持而已,因為grep把這些擴展元字符看成是普通符號,如果要想支持這些元字符,則可以使用 egrep 或 grep -E 命令。所以我們又把這些元字符稱作擴展元字符。
如果査詢 egrep 命令的幫助,對 egrep 的說明就是和 grep -E 一樣的命令,
Shell 中支持的擴展元字符。
擴展元字符 |
描述 |
+ |
匹配前面的一個字符或子表達式1次或任意多次。 egrep “go+gle” filename或grep -E “go+gel” filename |
? |
匹配前面的一個字符或子表達式零次或一次。例如:如 “colou?r” 可以匹配 “colour” 或 “color” |
| |
表示或。如“was|his”既會匹配包含“was”的行,或匹配包含“his”的行 |
() |
將括號里的內容看成是一個整體。可以理解為由多個單個字符組成的大字符。 |
注:"+"、"?"、"|"、"()"、"{}"等擴展元字符egrep命令或grep -E是支持的。grep命令在不加-E選項的情況下可以按如下格式寫:"\+"、"\?"、"\|"、"\(\)"、"\{\}"
2、正則表達式范例
下面舉例來說明這些元字符的作用。我們已經學習過的 grep 命令支持正則表達式,所以下面的練習都需要利用 grep 命令來演示。在使用 grep 命令開始練習之前,建議大家在 ~/.bashrc 文件中建立這個別名,如下:
[root@localhost ~]# vi /root/.bashrc
alias grep='grep --color=auto'
執行source命令使修改生效
[root@localhost ~]#source /root/.bashrc
這樣,grep 命令所匹配的字符都會使用顏色提示,更加容易理解正則表達式所具體匹配的字符串。
練習文件建立:
既然正則表達式是用來在文件中匹配字符串的,那么我們必須建立一個測試用的文件,才可以進行后續的實驗。文件如下:
[root@localhost ~]# cat test_rule.txt
Mr. Li Ming said:
he was the most honest man in LampBrother.
123despise him.
But since Mr. shen Chao came,
he never saaaid those words.
5555nice!
because,actuaaaally,
Mr. Shen Chao is the most honest man
Later,Mr. Li ming soid his hot body.
1、"*":前一個字符匹配0次或任意多次
注意,"*"和通配符中的"*"含義不同,它代表前一個字符重復 0 次或任意多次。比如,"a*"並不是匹配"a"后面的任意字符,而是可以匹配所有內容,包括空白行。我們試試:
為什么會這樣呢? "a*"代表匹配 0 個 a 或無數個 a,如果是匹配 0 個 a,也就是每個字符都會匹配,所以會匹配所有內容,包括空白行。所以"a*"這樣的正則表達式是沒有任何意義的。
如果這樣寫正則表達式"aa*",則代表這行字符串一定要有一個 a,但是后面有沒有 a 都可以。也就是說,會匹配至少包含一個 a 的行。
注:“*”修飾的它前面的一個字符a,而不是字符串aa
如果正則表達式是"aaa*",則會匹配最少包含兩個連續 a 的字符串。
2、".":匹配除換行符和回車符外的任意一個字符
正則表達式"."只能匹配一個字符,這個字符可以是任意字符。舉個例子:
# "s..d"會匹配在s和d這兩個字母之間一定有兩個字符的單詞
如果我想匹配在 s 和 d 字母之間有任意字符的單詞, 那么該怎么寫呢?"s*d"這個正則表達式肯定是不行的,因為它會匹配包含 d 字符的行,s*可以匹配任何字符。正確的寫法應該是"s.*d"。例如:
3、"^":匹配行首,"$":匹配行尾
"^":代表匹配行首,比如"^M"會匹配以大寫"M"開頭的行。
"$"代表匹配行尾,比如"n$"會匹配以小寫"n"結尾的行。
注意,如果文檔是在 Windows 中寫入的,那么"M$"是不能正確執行的,因為在 Windows 中換行符是"^M$",而在 Linux 中換行符是"$"。因為換行符不同,所以不能正確判斷行結尾字符串。那怎么解決呢?也很簡單,執行命令"dos2unix 文件名"把文檔格式轉換為 Linux 格式即可。如果沒有這個命令,則只需安裝 dos2unix 這個 RPM 包即可。
而"^$"則會匹配空白行。
如果不加"-n"選項,空白行是沒有任何顯示的;加入了"-n"能看到空白行的行號。
4、"[]":匹配中括號中指定的任意一個字符,且只匹配一個字符
"[]"會匹配中括號中指定的任意一個字符,注意只能匹配一個字符。比如 [ao] 要么匹配 a 字符,要么匹配一個 o 字符。
而"[0-9]"會匹配任意一個數字,例如:
#列出包含有數字的行
而"[A-Z]"則會匹配任意一個大寫字母,如果正則表達式是"^[a-z]",則代表匹配以小寫字母開頭的行。
"[^]":匹配除中括號的字符以外的任意一個字符
這里需要注意,如果"^"在 [] 外,則代表的是行首;如果在 [] 內,則代表的是取反。比如"^[a-z]"會匹配以小寫字母開頭的行,而"^[^a-z]"會匹配不以小寫字母開頭的行。
而"^[^a-zA-Z]"會匹配不以字母開頭的行。
5、:"\":轉義符
轉義符會取消特殊符號的含義。如果想要匹配使用"."結尾的行,那么正則表達式是".$"是不行的,因為"."在正則表達式中有特殊含義,代表任意一個字符。所以需要在前面加入轉義符,如"\.$"。
6、"\{n\}":表示其前面的字符出現 n 次
"\{n\}"中的 n 代表數字,這個正則表達式會匹配前一個字符出現 n 次的字符串,比如"zo\{3\}m"只能匹配"zooom"這個字符串。例如,"a\{3\}"就會匹配 a 字母連續出現 3 次的字符串。
如果正則表達式是"[0-9]\{3\}",則會匹配包含三個連續數字的字符串。
雖然"5555"有四個連續的數字,但是包含三個連續的數字,所以也是可以列出的。
只匹配以連續三個數字開頭,后面緊跟小寫字母的行,
"\{n,\}"表示其前面的字符出現不少於 n 次。
#匹配最少以連續三個數字開頭的行
"\{n,m\}"表示其前面的字符至少出現n次,最多出現m次。
#匹配在字母s和字母i之間最少有一個a、最多有3個a的字符串
例1:顯示sshd_config文件中有效的配置項
[root@localhost ~]# egrep -v "^#|^$" /etc/ssh/sshd_config
或
[root@localhost ~]# grep -E -v "^#|^$" /etc/ssh/sshd_config
例2:過濾IP地址
在/tmp/hosts文件記錄着相關ip地址信息,內容如下:
利用正則表達式過濾出ip地址
答案有很多種,提示:
提示 :IP地址從0-255之間,要把0-255拆分成0-99,100-199,200-249,250-255,然后在分別過濾出4段就出來了。正則表達式書寫如下所示:
例3:過濾手機號
在/tmp/phone_number文件中存放着電話碼信息,內容如下
# cat /tmp/phone_number.txt
13421391020
13521591629
1354243919046
15421391020
16421391020
42456789898
198384732947
利用正則表達式過濾出正確的電話號碼