正則表達(dá)式:定義的模式模板(pattern template),Linux工具可以用它來過濾文本懒构。
如果匹配了定義的模式,它就會被接受并進(jìn)一步處理耘擂;如果數(shù)據(jù)不匹配模式胆剧,它就會被濾掉。
在Linux中,有兩種流行的正則表達(dá)式引擎:
? POSIX基礎(chǔ)正則表達(dá)式(basic regular expression秩霍, BRE)引擎
? POSIX擴(kuò)展正則表達(dá)式(extended regular expression篙悯, ERE)引擎
BRE模式--純文本
正則表達(dá)式第一條原則就是:'正則表達(dá)式模式都區(qū)分大小寫。
$ echo "The books are expensive" | sed -n '/book/p'
The books are expensive
BRE模式--特殊字符
正則表達(dá)式識別的特殊字符包括:
.*[]^${}\+?|()
特殊字符作為文本字符铃绒,就必須轉(zhuǎn)義鸽照,轉(zhuǎn)義字符:是反斜線(\)。
$ echo "3 / 2" | sed -n '/\//p'
3 / 2
BRE模式--錨字符
- 鎖定在行首
脫字符(^)定義從數(shù)據(jù)流中文本行的行首開始的模式颠悬。
$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test
// 如果指定正則表達(dá)式模式時只用了脫字符矮燎,就不需要用反斜線來轉(zhuǎn)義。但如果你在模式中先指定了脫字符赔癌,隨后還有其他一些文本诞外,那么你必須在脫字符前用轉(zhuǎn)義字符。
- 鎖定在行尾
特殊字符美元符($)定義了行尾錨點灾票。
$ echo "This is a good book" | sed -n '/book$/p'
This is a good book
// 要想匹配峡谊,文本模式必須是行的最后一部分。比如 sed -n '/boo$/p' 就不能實現(xiàn)匹配
- 組合錨點
行首和行尾同時使用刊苍。
$ cat data5
This is one test line.
This is another test line.
$ sed '/^$/d' data5
This is one test line.
This is another test line.
BRE模式--點號字符
特殊字符點號用來匹配除換行符之外的任意單個字符既们。它必須匹配一個字符,如果在點號字符的位置沒有字符正什,那么模式就不成立啥纸。
$ cat data6
This is a test of a 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.
$ sed -n '/.at/p' data6
The cat is sleeping.
That is a very nice hat.
This test is at line four.
// 'cat' 'hat' ' at' 都可以匹配;而'a t'不能匹配埠忘。
BRE模式--字符組
字符組中必須有個字符來匹配相應(yīng)的位置。
$ cat data7
This line doesn't contain a number.
This line has 1 number on it.
This line a number 2 on it.
This line has a number 4 on it.
$ sed -n '/[0123]/p' data7
This line has 1 number on it.
This line a number 2 on it.
如果要確保只匹配五位數(shù)馒索,就必須將匹配的字符和其他字符分開莹妒,要么用空格,要么指明它們就在行首和行尾绰上。
$ sed -n '
> /^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p
> ' data8
60633
46201
22203
// 過濾出data8中只有5個字符的郵編旨怠。
字符組的一個極其常見的用法是"解析拼錯的單詞",比如用戶表單輸入的數(shù)據(jù)蜈块。
$ cat data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.
$ sed -n '
> /maint[ea]n[ae]nce/p
> /sep[ea]r[ea]te/p
> ' data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.
BRE模式--排除型字符組
可以尋找組中沒有的字符鉴腻,而不是去尋找組中含有的字符。
$ sed -n '/[^ch]at/p' data6
This test is at line four.
BRE模式--特殊的字符組
組 描 述
[[:alpha:]] 匹配任意字母字符百揭,不管是大寫還是小寫
[[:alnum:]] 匹配任意字母數(shù)字字符0~9爽哎、 A~Z或a~z
[[:blank:]] 匹配空格或制表符
[[:digit:]] 匹配0~9之間的數(shù)字
[[:lower:]] 匹配小寫字母字符a~z
[[:print:]] 匹配任意可打印字符
[[:punct:]] 匹配標(biāo)點符號
[[:space:]] 匹配任意空白字符:空格、制表符器一、 NL课锌、 FF、 VT和CR
[[:upper:]] 匹配任意大寫字母字符A~Z
$ echo "abc" | sed -n '/[[:digit:]]/p'
$
$ echo "abc" | sed -n '/[[:alpha:]]/p'
abc
$ echo "abc123" | sed -n '/[[:digit:]]/p'
abc123
$ echo "This is, a test" | sed -n '/[[:punct:]]/p'
This is, a test
BRE模式--區(qū)間
可以用單破折線符號在字符組中表示字符區(qū)間。
$ sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8
60633
46201
45902
也適用于字母渺贤。
$ sed -n '/[c-h]at/p' data6
The cat is sleeping.
That is a very nice hat.
可以在單個字符組指定多個不連續(xù)的區(qū)間雏胃。
$ sed -n '/[a-ch-m]at/p' data6
The cat is sleeping.
That is a very nice hat.
BRE模式--星號
在字符后面放置星號表明該字符必須在匹配模式的文本中出現(xiàn)0次或多次。
$ echo "I ate a potatoe with my lunch." | sed -n '/potatoe*/p'
I ate a potatoe with my lunch.
將點號特殊字符和星號特殊字符組合起來志鞍。這個組合能夠匹配任意數(shù)量的任意字符瞭亮。它通常用在數(shù)據(jù)流中兩個可能相鄰或不相鄰的文本字符串之間。
$ echo "this is a regular pattern expression" | sed -n '
> /regular.*expression/p'
this is a regular pattern expression
擴(kuò)展--問號
問號表明前面的字符可以出現(xiàn)0次或1次固棚,但只限于此统翩。它不會匹配多次出現(xiàn)的字符。
$ echo "bt" | gawk '/be?t/{print $0}'
bt
$ echo "bet" | gawk '/be?t/{print $0}'
bet
擴(kuò)展--加號
加號表明前面的字符可以出現(xiàn)1次或多次玻孟,但必須至少出現(xiàn)1次唆缴。如果該字符沒有出現(xiàn),那么模式就不會匹配黍翎。
$ echo "beeet" | gawk '/be+t/{print $0}'
beeet
$ echo "beet" | gawk '/be+t/{print $0}'
beet
$ echo "bet" | gawk '/be+t/{print $0}'
bet
$ echo "bt" | gawk '/be+t/{print $0}'
$
擴(kuò)展--花括號
間隔(interval)面徽,可以用兩種格式來指定區(qū)間。
? m:正則表達(dá)式準(zhǔn)確出現(xiàn)m次匣掸。
? m, n:正則表達(dá)式至少出現(xiàn)m次趟紊,至多n次。
這個特性可以精確調(diào)整字符或字符集在模式中具體出現(xiàn)的次數(shù)碰酝。
// 默認(rèn)情況下霎匈, gawk程序不會識別正則表達(dá)式間隔。必須指定gawk程序的--re- interval命令行選項才能識別正則表達(dá)式間隔送爸。
$ echo "bt" | gawk --re-interval '/be{1}t/{print $0}'
$
$ echo "bet" | gawk --re-interval '/be{1}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1}t/{print $0}'
$
字符e可以出現(xiàn)1次或2次铛嘱,這樣模式就能匹配;否則袭厂,模式無法匹配:
$ echo "bet" | gawk --re-interval '/be{1,2}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1,2}t/{print $0}'
beet
擴(kuò)展--管道符號
管道符號允許你在檢查數(shù)據(jù)流時墨吓,用邏輯OR方式指定正則表達(dá)式引擎要用的兩個或多個模式。
使用管道符號的格式如下:
expr1|expr2|...
$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
The cat is asleep
$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}'
The dog is asleep
$ echo "The sheep is asleep" | gawk '/cat|dog/{print $0}'
$
這個例子會匹配數(shù)據(jù)流文本中的cat纹磺、 hat或dog帖烘。
$ echo "He has a hat." | gawk '/[ch]at|dog/{print $0}'
He has a hat.
擴(kuò)展--表達(dá)式分組
可以用圓括號()進(jìn)行分組。
$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday
結(jié)尾的urday分組以及問號橄杨,使得模式能夠匹配完整的Saturday或縮寫Sat秘症。
將分組和管道符號一起使用來創(chuàng)建可能的模式匹配組是很常見的做法:
$ echo "cat" | gawk '/(c|b)a(b|t)/{print $0}'
cat
$ echo "cab" | gawk '/(c|b)a(b|t)/{print $0}'
cab
$ echo "bat" | gawk '/(c|b)a(b|t)/{print $0}'
bat
$ echo "bab" | gawk '/(c|b)a(b|t)/{print $0}'
bab
$ echo "tab" | gawk '/(c|b)a(b|t)/{print $0}'
$
$ echo "tac" | gawk '/(c|b)a(b|t)/{print $0}'
$
總結(jié)與補充
基本正則
grep 'partern'
擴(kuò)展正則
grep -E 'partern'
perl正則(更強的正則)
grep -P 'partern'
1.必記的常用元字符:
.匹配除換行符以外的任意字符
\w 匹配字母或數(shù)字或下劃線或漢字 \W表示與之相反
\s匹配任意的空白符\S表示與之相反
\d匹配數(shù)字\D表示與之相反
\b匹配單詞的開始或結(jié)束\B表示與之相反
^匹配字符串的開始
$匹配字符串的結(jié)束
[x] 匹配字符x [^x]表示出來字符x以外的任意字符
[aeiou] 匹配英語中的元音字母 [^aeiou]表示除了元音字母以外的所有字符
實例
[root@hadoop ~]# cat test.txt
hello
998
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\w'
hello
998
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\W'
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\s'
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\S'
hello
998
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\d'
998
44.5
[root@hadoop ~]# cat test.txt | grep -P '\D'
hello
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\b'
hello
998
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\B'
hello
998
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '^$'
[root@hadoop ~]#
2.必記的常用限定符
- 重復(fù)零次或更多次
- 重復(fù)一次或更多次
? 重復(fù)零次或一次
{n} 重復(fù)n次
{n,} 重復(fù)n次或更多次
{n,m} 重復(fù)n到m次
3.必記的常用分組語法
小括號表示一個子表達(dá)式,匹配這個子表達(dá)式也就是捕獲匹配到的文本式矫,默認(rèn)情況下乡摹,每個分組會自動擁有一個組號,
規(guī)則是:從左向右采转,以分組的左括號為標(biāo)志趟卸,第一個出現(xiàn)的分組的組號為1,第二個為2,以此類推锄列,
組號分配過程是要從左向右掃描兩遍的:第一遍只給未命名組分配图云,第二遍只給命名組分配--因此所有命名組的組號都大于未命名的組號
3.1捕獲
(exp) 匹配exp,并捕獲文本到自動命名的組里 \b(\w+)\b\s+\1\b可以用來匹配重復(fù)的單詞,像go go, 或者kitty kitty
[root@hadoop ~]# echo 'kitty kitty' | grep -oE '\b(\w+)\b\s+\1\b'
kitty kitty
(?<name>exp)匹配exp,并捕獲文本到名稱為name的組里邻邮,也可以寫成(?'name'exp)
上面的正則指定組名竣况,可以寫成\b(?<Word>\w+)\b\s+\k<Word>\b
(?:exp) 匹配exp,不捕獲匹配的文本,也不給此分組分配組號
[root@hadoop ~]# echo 'kitty kitty' | grep -oP '\b(?<wox>\w+)\b\s+\k<wox>\b'
kitty kitty
(?:@\w)binguo\w匹配@開頭包含binguo的字符串
(?:exp)不會改變正則表達(dá)式的處理方式筒严,只是這樣的組匹配的內(nèi)容不會像前兩種那樣被捕獲到某個組里面丹泉,也不會擁有組號
3.2零寬斷言
(?=exp) 匹配exp前面的位置
\b\w+(?=ing\b) I'm singing while you're dancing 匹配sing和danc
(?<=exp)匹配exp后面的位置
(?<=\bre)\w+\b reading a book 匹配ading
[root@hadoop ~]# ifconfig | grep -oP '(?<=inet addr:).*(?=Bcast)'
192.168.121.128
[root@hadoop ~]# ifconfig | grep -oP '(?=inet addr:).*(?<=Bcast)'
inet addr:192.168.121.128 Bcast
[root@hadoop ~]# ifconfig | grep -oP '(?<=inet addr:).*(?<=Bcast)'
192.168.121.128 Bcast
(?<=\s)\d+(?=\s)匹配以空白符間隔的數(shù)字(再次強調(diào),不包括這些空白符)
[root@hadoop ~]# echo "nihao 9527 hello" | grep -P '(?<=\s)\d+(?=\s)'
nihao 9527 hello
(?!exp) 匹配后面跟的不是exp的位置
需求:獲取不是.exe后綴文件不含后綴的文件名
[root@hadoop ~]# cat files.test
notexefile1.txt
exefile1.exe
exefile2.exe
exefile3.exe
notexefile2.php
notexefile3.sh
[root@hadoop ~]# cat files.test | grep -oP '(.+)(?!\.exe)\.[\S]+$'
notexefile1.txt
notexefile2.php
notexefile3.sh
(?<!exp)匹配前面不是exp的位置
需求:獲取不是name參數(shù)的值
[root@hadoop ~]# cat form.txt
name=zhangsan
password=123456
---------------
age=26
sex=man
[root@hadoop ~]# cat form.txt | grep -oP '^[^=]+=(?<!name=)(.+)'
password=123456
age=26
sex=man
3.3注釋
(?#comment)這種類型的分組不對正則表達(dá)式的處理產(chǎn)生任何影響鸭蛙,用于提供注釋讓人閱讀
4.必記的懶惰限定符
*? 重復(fù)任意次摹恨,但盡可能少重復(fù)
+? 重復(fù)1次或更多次,但盡可能少重復(fù)
貪婪匹配:在使整個表達(dá)式能得到匹配的前提下娶视,匹配盡可能多的字符
a.*b晒哄,它將會匹配最長的以a開始,以b結(jié)束的字符串肪获。如果用它來搜索aabab的話寝凌,它會匹配整個字符串a(chǎn)abab。
懶惰(非貪婪)匹配:
也就是匹配盡可能少的字符孝赫,《2.必記的常用限定符》提到的限定符都可以被轉(zhuǎn)化為懶惰匹配模式较木,只要在它后面加上一個問號?
a.*?b,匹配最短的青柄,以a開始伐债,以b結(jié)束的字符串。
如果把它應(yīng)用于aabab的話致开,它會匹配aab(第一到第三個字符)和ab(第四到第五個字符)
為什么第一個匹配的是aab(第一到第三個字符)而不是ab(第二到第三個字符)?
簡單地說峰锁,因為正則表達(dá)式有另一條規(guī)則,比懶惰/貪婪規(guī)則的優(yōu)先級更高:最先開始的匹配擁有最高的優(yōu)先權(quán)
[root@hadoop ~]# echo '<div>test1</div>bb<div>test2</div>' | grep -oP '<div>.*</div>'
<div>test1</div>bb<div>test2</div>
[root@hadoop ~]# echo '<div>test1</div>bb<div>test2</div>' | grep -oP '<div>.*?</div>'
<div>test1</div>
<div>test2</div>
闖關(guān)模式實踐
http://regex.alf.nu 闖關(guān)模式練習(xí)正則表達(dá)式喇喉,完成一個個正則匹配的測驗
http://regexone.com/ 通過實際練習(xí)掌握正則表達(dá)式
https://regexcrossword.com/ 正則挑戰(zhàn)祖今,有不同難度校坑,很豐富
http://callumacrae.github.io/regex-tuesday/ 正則挑戰(zhàn)拣技,完成正則匹配要求
作者:豆約翰
鏈接:http://www.reibang.com/p/e48e2fcd14ff
來源:簡書
簡書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處耍目。