導(dǎo)覽
正則表達(dá)式模式
^:錨定行首
$:錨定行尾
.:特殊字符點(diǎn)號(hào)用來匹配換行符之外的任意單個(gè)字符,至少一個(gè)字符。
[]:字符組,配置方括號(hào)內(nèi)的字符或數(shù)字,[ch],[Yy]
[^]:不包含字符組內(nèi)的字符,[^ch]
區(qū)間:[c-h],[0-9]匹配c到h之間的單詞特殊字符組:
[[:alpha:]]匹配任意字母字符,不管是大寫還是小寫
[[:alnum:]]匹配任意字母數(shù)字字符0~9、 AZ或az
[[:blank:]]匹配空格或制表符
[[:digit:]]匹配0~9之間的數(shù)字
[[:lower:]]匹配小寫字母字符a~z
[[:print:]]匹配任意可打印字符
[[:punct:]]匹配標(biāo)點(diǎn)符號(hào)
[[:space:]]匹配任意空白字符:空格、制表符、 NL、 FF、 VT和CR
[[:upper:]]匹配任意大寫字母字符A~Z
*:匹配模式的文本中出現(xiàn)0次或多次擴(kuò)展的正則表達(dá)式(gawk)
?:匹配前面的字符出現(xiàn)0次或1次
+:配置前面的字符出現(xiàn)1次或多次
{m}:配置至少出現(xiàn)m次
{,n}:配置至多出現(xiàn)n次
{m,n}:配置至少m次,至多n次
|用邏輯OR方式指定正則表達(dá)式引擎要用的兩個(gè)或多個(gè)模式。
():表達(dá)式分組,正則表達(dá)式模式也可以用圓括號(hào)進(jìn)行分組。當(dāng)你將正則表達(dá)式模式分組時(shí),該組會(huì)被視為一個(gè)標(biāo)準(zhǔn)字符??梢韵駥?duì)普通字符一樣給該組使用特殊字符
--re- interval默認(rèn)情況下, gawk程序不會(huì)識(shí)別正則表達(dá)式間隔。必須指定gawk程序的--re- interval命令行選項(xiàng)才能識(shí)別正則表達(dá)式間隔。
20.1 什么是正則表達(dá)式
20.1.1 定義
正則表達(dá)式是你定義的、Linux工具用來過濾文本的模式模板。正則表達(dá)式模式利用通配符來代表數(shù)據(jù)流中的一個(gè)或者多個(gè)字符

20.1.2 正則表達(dá)式類型
在Linux中,有兩種流行的正則表達(dá)式引擎:
- POSIX基礎(chǔ)正則表達(dá)式(BRE)引擎
sed - POSIX擴(kuò)展正則表達(dá)式(ERE)引擎
gawk
20.2 定于BRE模式
20.2.1 純文本
[ttxie@41 ~]$ echo "This is a test" |sed -n '/test/p'
This is a test
[ttxie@41 ~]$ echo "This is a test" |sed -n '/trial/p'
[ttxie@41 ~]$ echo "This is a test" |awk '/test/{print $0}'
This is a test
[ttxie@41 ~]$ echo "This is a test" |awk '/trial/{print $0}'
正則表達(dá)式并不關(guān)心模式在數(shù)據(jù)流中的位置,也不關(guān)心出現(xiàn)了多少次,只要匹配了就會(huì)將該字符串傳會(huì)linux工具。
正則表達(dá)式模式區(qū)分大小寫。
[ttxie@41 ~]$ echo "This is a test" |sed -n '/this/p'
[ttxie@41 ~]$ echo "This is a test" |sed -n '/This/p'
This is a test
模糊匹配
只要定義的文本出現(xiàn)在數(shù)據(jù)流中,正則就能匹配,反之則不成立
[ttxie@41 ~]$ echo "The books are expensive" |sed -n '/book/p'
The books are expensive
[ttxie@41 ~]$ echo "The book are expensive" |sed -n '/books/p'
20.2.2 特殊字符
正則表達(dá)式識(shí)別的特殊字符包括:.*[]^${}\+?|(),如果要用某個(gè)特殊字符作為文本字符,就必須轉(zhuǎn)義。在前面加上反斜線\。
[ttxie@41 ~]$ echo "This cost is \$200" |sed -n '/\$/p'
This cost is $200
要使用正斜線也需要用轉(zhuǎn)義字符
[ttxie@41 ~]$ echo "3 / 2" |sed '/\//p'
3 / 2
20.2.3 錨字符 ^ $
默認(rèn)情況下,模式出現(xiàn)再數(shù)據(jù)流中的任何地方,它就能匹配。
有兩個(gè)特殊字符可以用來將模式鎖定在數(shù)據(jù)流中的行首或行尾。
20.2.3.1.鎖定在行首(脫字符 ^)
^ 定義從數(shù)據(jù)流中文本行的行首開始的模式。如果模式出現(xiàn)在行首之外的位置,正則表達(dá)式模式則無法匹配。
需要用^,就必須將它放在正則表達(dá)式中指定的模式前面。
[ttxie@41 ~]$ echo "The book store" |sed -n '/^book/p'
[ttxie@41 ~]$ echo "Books are great" |sed -n '/^Book/p'
Books are great
還可以輸入文件:
$sed -n ‘/^this/p’ data.txt
data.txt 中以this開頭的行就能找出來。
注意如果將^放到模式開頭之外的其他位置,那么就跟普通字符一樣了。
[ttxie@41 ~]$ echo "This is ^ test" |sed -n '/s ^/p'
This is ^ test
注意:
如果指定正則表達(dá)式模式時(shí)只用了脫字符,就不需要用反斜線來轉(zhuǎn)義。
如果你在模式中先指定了脫字符,隨后還有一些其他文本,那么你必須在脫字符前用轉(zhuǎn)義字符。
20.2.3.2. 鎖定在行尾
用美元符$
[ttxie@41 ~]$ echo "This is a good book" |sed -n '/book$/p'
This is a good book
[ttxie@41 ~]$ echo "This is a good book" |sed -n '/good$/p'
[ttxie@41 ~]$ echo "This is a good book" |sed -n '/books$/p'
要想匹配,文本模式必須是行的最后一部分。
20.2.3.3. 組合錨點(diǎn)
比如想到匹配指定內(nèi)容
$sed ‘/^this is test line$/p’ data.txt匹配行 this is test line將兩個(gè)錨點(diǎn)直接組合在一起,之間不加任何東西,這樣就過濾出數(shù)據(jù)流中的空白行。
$sed -n ‘/^$/p’ data.txt 這樣可以把data.txt 中的空白行過濾出來。
- 過濾掉空白行
[ttxie@41 part20]$ cat data5.txt
This is one line
this is another line
[ttxie@41 part20]$ sed '/^$/d' data5.txt
This is one line
this is another line
20.2.4 點(diǎn)號(hào)字符 .
用來匹配除換行符之外的任意單個(gè)字符。它必須匹配一個(gè)字符,如果點(diǎn)字符的位置沒有字符那么模式就不成立。
[ttxie@41 part20]$ cat data6.txt
this is a test line
the cat is sleeping
that is a very nice hat
this test is at line four
at ten o'clock we'll go home
[ttxie@41 part20]$ sed -n '/.at/p' data6.txt
the cat is sleeping
that is a very nice hat
this test is at line four
第4行空格也算一個(gè)字符。注意第5行沒有匹配到。at前面沒有字符了。
20.2.5 字符組 []
可以限定待匹配的具體字符,在正則表達(dá)式中,這稱為字符組。用[]括起來
[ttxie@41 part20]$ cat data6.txt
this is a test line
the cat is sleeping
that is a very nice hat
this test is at line four
at ten o'clock we'll go home
[ttxie@41 part20]$ sed -n '/[ch]at/p' data6.txt
the cat is sleeping
that is a very nice hat
相當(dāng)于只匹配cat 或者 hat。其他的at就不匹配了。
在不確定大小寫的時(shí)候,字符組會(huì)非常有用:
[ttxie@41 part20]$ echo "yes" |sed -n '/[Yy]es/p'
yes
[ttxie@41 part20]$ echo "Yes" |sed -n '/[Yy]es/p'
Yes
還可以用多個(gè)字符組:
[ttxie@41 part20]$ echo "Yes" |sed -n '/[Yy][Ee][Ss]/p'
Yes
[ttxie@41 part20]$ echo "yEs" |sed -n '/[Yy][Ee][Ss]/p'
yEs
[ttxie@41 part20]$ echo "yES" |sed -n '/[Yy][Ee][Ss]/p'
yES
這樣就相當(dāng)于可以限制行的字符個(gè)數(shù)和區(qū)間了
20.2.6 排除型字符組
相當(dāng)于字符組取反,可以尋找字符組中沒有的字符。在前面加個(gè)脫字符就好了。
[ttxie@41 part20]$ cat data6.txt
this is a test line
the cat is sleeping
that is a very nice hat
this test is at line four
at ten o'clock we'll go home
[ttxie@41 part20]$ sed -n '/[^ch]at/p' data6.txt
this test is at line four
匹配出c和h以外的字符。由于空格字符屬于這個(gè)范疇,所以它通過了模式匹配,但即使是排除,字符組必須匹配一個(gè)字符,所以以at為開頭的行仍然未能通過匹配。
20.2.7 區(qū)間
- 0 – 9,可以直接這么寫[0-9] 而不需要[0123456789]
[ttxie@41 part20]$ cat data_num.txt
60633
46201
223001
4353
22203
[ttxie@41 part20]$ sed -n '/[0-9][0-9][0-9][0-9][0-9]/p' data_num.txt
60633
46201
223001
22203
[ttxie@41 part20]$ sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data_num.txt
60633
46201
22203
第一種:它成功過濾掉了過短的數(shù)字,但是因?yàn)樽詈笠粋€(gè)字符組沒有字符可匹配,它也通過了6位數(shù)字的;
第二種:指明它的行首和行尾,可以確保只匹配五位數(shù)。
- 字母也可以
匹配c到h這個(gè)區(qū)間的字符。
[ttxie@41 part20]$ cat data6.txt
this is a test line
the cat is sleeping
that is a very nice hat
this test is at line four
at ten o'clock we'll go home
[ttxie@41 part20]$ sed -n '/[c-h]at/p' data6.txt
the cat is sleeping
that is a very nice hat
還可以指定多個(gè)不連續(xù)的區(qū)間:指定 a-c 和 h-m區(qū)間的字母
[ttxie@41 part20]$ sed -n '/[a-ch-m]at/p' data6.txt
the cat is sleeping
that is a very nice hat
20.2.8 特殊的字符組
除了自定義的區(qū)間(比如[0-9] [a-f])之外,BRE還包含了一些特殊的字符組。見下表

使用:
[ttxie@41 part20]$ echo "abc" |sed -n '/[[:digit:]]/p'
[ttxie@41 part20]$ echo "abc" |sed -n '/[[:alpha:]]/p'
abc
[ttxie@41 part20]$ echo "abc123" |sed -n '/[[:digit:]]/p'
abc123
[ttxie@41 part20]$ echo "This is , a test" |sed -n '/[[:punct:]]/p'
This is , a test
20.2.9 星號(hào) *
在字符后面放置星號(hào)用來表明該字符必須在匹配模式的文本中出現(xiàn)0次或多次。
[ttxie@41 part20]$ echo "ik" |sed -n '/ie*k/p' ##出現(xiàn)0次
ik
[ttxie@41 part20]$ echo "iek" |sed -n '/ie*k/p'
iek
[ttxie@41 part20]$ echo "ieek" |sed -n '/ie*k/p'
ieek
*還能用到字符組上,它允許指定可能在文本中出現(xiàn)多次的字符組或區(qū)間:
[ttxie@41 part20]$ echo "bt" |sed -n '/b[ae]*t/p'
bt
[ttxie@41 part20]$ echo "bat" |sed -n '/b[ae]*t/p'
bat
[ttxie@41 part20]$ echo "bet" |sed -n '/b[ae]*t/p'
bet
[ttxie@41 part20]$ echo "btt" |sed -n '/b[ae]*t/p'
btt
[ttxie@41 part20]$ echo "baat" |sed -n '/b[ae]*t/p'
baat
[ttxie@41 part20]$ echo "baaeeeet" |sed -n '/b[ae]*t/p'
baaeeeet
[ttxie@41 part20]$ echo "baaeeaeet" |sed -n '/b[ae]*t/p'
baaeeaeet
[ttxie@41 part20]$ echo "baaekaeet" |sed -n '/b[ae]*t/p'
[ttxie@41 part20]$ echo "baaetaeet" |sed -n '/b[ae]*t/p'
baaetaeet
出現(xiàn)t也行?
20.3 擴(kuò)展正則表達(dá)式(POSIX ERE)
提供了一些可以供linux應(yīng)用和工具使用的額外符號(hào)。
gawk程序能夠識(shí)別ERE模式(會(huì)慢一點(diǎn)),sed編輯器不能識(shí)別(查找比較快)。
20.3.1 問號(hào)?
類似于星號(hào),但是有點(diǎn)不同。
- 問號(hào)表明前面的字符可以出現(xiàn)0次或1次,不會(huì)匹配出現(xiàn)多次的字符。
[ttxie@41 part20]$ echo "bt" |gawk '/be?t/{print $0}'
bt
[ttxie@41 part20]$ echo "bet" |gawk '/be?t/{print $0}'
bet
[ttxie@41 part20]$ echo "beeet" |gawk '/be?t/{print $0}' #e 出現(xiàn)了2次,這里就不輸出了
- 還可以跟字符組一起使用:
[ttxie@41 part20]$ echo "bt" |gawk '/b[ae]?t/{print $0}'
bt
[ttxie@41 part20]$ echo "bat" |gawk '/b[ae]?t/{print $0}'
bat
[ttxie@41 part20]$ echo "bet" |gawk '/b[ae]?t/{print $0}'
bet
[ttxie@41 part20]$ echo "baet" |gawk '/b[ae]?t/{print $0}'
[ttxie@41 part20]$ echo "baat" |gawk '/b[ae]?t/{print $0}'
[ttxie@41 part20]$ echo "bot" |gawk '/b[ae]?t/{print $0}'
如果字符組中的字符出現(xiàn)了0次或1次,模式匹配就成立,但如果兩個(gè)字符都出現(xiàn)了,或者一個(gè)字符出現(xiàn)了2次,模式匹配就不成立。
20.3.2 加號(hào)+
有點(diǎn)像*號(hào)。但是必須出現(xiàn)1次以上。可以有多次,但必須至少出現(xiàn)1次。
[ttxie@41 part20]$ echo "bt" |gawk '/be+t/{print $0}'
[ttxie@41 part20]$ echo "bet" |gawk '/be+t/{print $0}'
bet
[ttxie@41 part20]$ echo "beeeet" |gawk '/be+t/{print $0}'
beeeet
20.3.3 使用花括號(hào){}
花括號(hào)允許你為可重復(fù)的正則表達(dá)式指定一個(gè)上限,這通常稱為間隔??梢杂脙煞N格式來指定區(qū)間。
1)m:正則表達(dá)式準(zhǔn)確出現(xiàn)m次
2)m,n:正則表達(dá)式至少出現(xiàn)m次,至多n次。
注意:默認(rèn)情況下gawk程序不識(shí)別正則表達(dá)式間隔。必須指定gawk程序的–re-interval命令行選項(xiàng)才能識(shí)別正則表達(dá)式間隔。
[ttxie@41 part20]$ echo "bet" |gawk --re-interval '/be{1}t/{print $0}'
bet
[ttxie@41 part20]$ echo "bet" |gawk --re-interval '/be{1,2}t/{print $0}'
bet
[ttxie@41 part20]$ echo "beet" |gawk --re-interval '/be{1,2}t/{print $0}'
beet
[ttxie@41 part20]$ echo "beeeet" |gawk --re-interval '/be{1,2}t/{print $0}'
- 也適用于字符組
[ttxie@41 part20]$ echo "bt" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
[ttxie@41 part20]$ echo "bat" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bat
[ttxie@41 part20]$ echo "bet" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bet
[ttxie@41 part20]$ echo "baet" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
baet
[ttxie@41 part20]$ echo "baat" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
baat
[ttxie@41 part20]$ echo "baaeet" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
[ttxie@41 part20]$ echo "beaest" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'
如果a或e單獨(dú)持續(xù)1次或2次,模式匹配;ae組合出現(xiàn)1次模式匹配;否則,模式匹配失敗;
20.3.4 管道符號(hào)|
管道符號(hào)允許你在檢查數(shù)據(jù)流時(shí),用邏輯or方式指定正則表達(dá)式引擎要用的兩個(gè)或多個(gè)模式。
格式如下:expr1|expr2|……
[ttxie@41 part20]$ echo "The dog is asleep" |gawk '/cat|dog/{print $0}'
The dog is asleep
[ttxie@41 part20]$ echo "The dog is asleep" |gawk '/cat|[dp]og/{print $0}'
The dog is asleep
20.3.5 表達(dá)式分組()
正則表達(dá)式模式也可以用圓括號(hào)進(jìn)行分組。
- 當(dāng)你將正則表達(dá)式模式分組時(shí),該組會(huì)被視為一個(gè)標(biāo)準(zhǔn)字符??梢韵駥?duì)普通字符一樣給該組使用特殊字符。
?是匹配0次或1次。
[ttxie@41 part20]$ echo "Sat" |gawk '/Sat(urday)?/{print $0}'
Sat
[ttxie@41 part20]$ echo "Saturday" |gawk '/Sat(urday)?/{print $0}'
Saturday
相當(dāng)于把urday當(dāng)做一個(gè)整體了, /SatF?/ 跟這個(gè)類似,F(xiàn)出現(xiàn)0次或1次。
- ()需要轉(zhuǎn)義的用法:
[ttxie@41 part20]$ echo "Sat(urday)" | gawk '/Sat\(urday\)/ {print $0}'
Sat(urday)
[ttxie@41 part20]$ echo "Saturday" | gawk '/Sat\(urday\)/ {print $0}'
還可以將分組和管道符號(hào)一起使用來創(chuàng)建可能的模式匹配組:
[ttxie@41 part20]$ echo "cat" | gawk '/(b|c)a(b|t)/ {print $0}'
cat
[ttxie@41 part20]$ echo "cat" | gawk '/[b|c]a[b|t]/ {print $0}'
cat
這樣相當(dāng)于匹配 bab bat cab cat 四種。
20.4 正則表達(dá)式實(shí)戰(zhàn)
20.4.1 目錄文件計(jì)數(shù)
這個(gè)例子用于對(duì)PATH環(huán)境變量中各個(gè)目錄里的可執(zhí)行文件進(jìn)行計(jì)數(shù):
[ttxie@41 part20]$ cat countfiles.sh
#!/bin/bash
mypath=$(echo $PATH | sed 's/:/ /g')
count=0
for dir in $mypath
do
check=$(ls $dir)
for item in $check
do
count=$[ count + 1 ]
done
echo "$dir - $count"
count=0
done
[ttxie@41 part20]$ bash countfiles.sh
/home/ttxie/miniconda2/bin - 0
/usr/local/bin - 0
/usr/bin - 1679
/usr/local/sbin - 0
/usr/sbin - 644
/home/ttxie/.local/bin - 0
/home/ttxie/bin - 0
20.4.2 驗(yàn)證電話號(hào)碼
美國(guó)的號(hào)碼格式如下:
(223)456-7890
(223) 456-7890
223-456-7890
223.456.7890
- 最開始可能有
(可以寫成:^\(? - 三位區(qū)號(hào)(第一位必須大于2):
[2-9][0-9]{2} - 然后又是括號(hào):
\)? - 然后是分隔符(無空格,有空格,點(diǎn),減號(hào)):
(| |-|\.)第一個(gè)|緊跟在(后面用來匹配沒有空格的情況。 - 然后是3位數(shù)字:[0-9]{3}
- 又是分隔符:( |-|.)
- 最后四位數(shù)字:[0-9]{4}
- 連起來就是:
^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$
[ttxie@41 part20]$ cat isPhone.sh
#!/bin/bash
gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$/{print $0}'
[ttxie@41 part20]$ echo "317-555-1234" |bash isPhone.sh
317-555-1234
[ttxie@41 part20]$ echo "0317-555-1234" |bash isPhone.sh
還可以將整個(gè)文件重定向到腳本:
phonelist里面存放著一行一行的數(shù)據(jù):
$cat phonelist | ./isphone
這個(gè)例子其實(shí)也不是特別合理,比如下面幾種情況也算是合法號(hào)碼:
(235.561-4430
- 451.4651
總之還是有待優(yōu)化。
20.4.3 解析郵件地址
郵件地址的形式如下:
username@hostname
- username值可用字母數(shù)字字符以及以下特殊字符:
- 點(diǎn)號(hào)
- 單破折線
- 加號(hào)
- 下劃線
- hostname部分由一個(gè)或多個(gè)域名和一個(gè)服務(wù)器名組成。只允許字母數(shù)字字符以及下面的特殊字符:比如(xiaochongyong@amwell-haha.com)
- 點(diǎn)號(hào)
- 下劃線
- username@相當(dāng)于:
^([a-zA-Z0-9_\-\.\+]+)@
注意: [] 里面是字符組,相當(dāng)于之前的[xcs]。() 里面是表達(dá)式分組
hostname相當(dāng)于:
([a-zA-Z0-9_\-\.\]+)后面還要接頂級(jí)域名。.com .cn .org 等
只能是字母字符,必須不少于兩個(gè)字符,長(zhǎng)度不超多5個(gè)字符:\.([a-zA-Z]{2,5})$
- 連起來就是:
^([a-zA-Z0-9_\.\-\+]+)@([a-zA-Z0-9_\.\-]+)\.([a-zA-Z]{2,5})$
[ttxie@41 part20]$ cat isemail.sh
#!/bin/bash
gawk --re-interval '/^([a-zA-Z0-9_\.\-\+]+)\@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/ {print $0}'
[ttxie@41 part20]$ echo "222x2iaochongyong@s1amwell-elec.com" | bash isemail.sh
222x2iaochongyong@s1amwell-elec.com
[ttxie@41 part20]$ echo "222x2iaocho%ngyong@s1amwell-elec.com" | bash isemail.sh
[ttxie@41 part20]$ echo "222x2iaocho%ngyong+@s1amwell-elec.com" |bash isemail.sh
20.5 小結(jié)
正則表達(dá)式定義了用來過濾數(shù)據(jù)流中文本的模式模板。
模式由標(biāo)準(zhǔn)文本字符和特殊字符的組成。
正則表達(dá)式引擎用特殊字符來匹配一系列單個(gè)或多個(gè)字符,這類似于其他應(yīng)用程序中通配符的工作方式