Linux命令行與Shell腳本編程 第十九章 正則表達式
文章目錄
- Linux命令行與Shell腳本編程 第十九章 正則表達式
- 九.正則表達式
- 9.1.正則表達式基礎
- 9.1.1.正則表達式的類型
- 9.2.定義BRE模式
- 9.2.1.普通文本
- 9.2.2.特殊字符
- 9.2.3.錨點字符
- 錨定行首^
- 錨定行尾$
- 組合錨點
- 9.2.4.點號字符\.
- 9.2.5.字符組[]
- 9.2.6.排除字符組
- 8.2.7.區間
- 9.2.8.特殊字符組
- 9.2.9.星號*
- 9.3.擴展正則表達式
- 9.3.1.問號?
- 9.3.2.加號+
- 9.3.3.花括號\{\}
- 9.3.4.豎線符號\|
- 9.3.5.表達式分組
- 9.4.實戰
- 9.4.1.目錄文件計數
九.正則表達式
- 正則表達式基礎
- 定義BRE模式
- 擴展正則表達式
在sed和gawk中創建正則表達式,以得到所需的數據。
9.1.正則表達式基礎
正則表達式是一種可供Linux工具過濾文本的自定義模板,使用元字符來描述數據流中的一個或多個字符.
Linux工具(比如sed或gawk)會在讀取數據時使用正則表達式對數據進行模式匹配。如果數據匹配模式,它就會被接受并進行處理。
正則表達式包含文本和/或特殊字符.
9.1.1.正則表達式的類型
不同的應用程序可能使用不同類型的正則表達式。
編程語言(Java、Python)、Linux工具(sed、gawk和grep)以及主流應用程序(MySQL數據庫服務器)。
正則表達式由正則表達式引擎實現。這種底層軟件,負責解釋正則表達式并用這些模式進行文本匹配。
Linux 中流行的兩種:
- POSIX基礎正則表達式(basic regular expression,BRE)引擎。
- POSIX擴展正則表達式(extended regular expression,ERE)引擎。
大多數Linux工具至少符合POSIX BRE引擎規范。但有些工具(比如sed)僅符合BRE引擎規范的一個子集。
(出于速度方面的考慮導致,sed希望盡可能快地處理數據流中的文本)
POSIX ERE引擎多見于依賴正則表達式過濾文本的編程語言中。為常見模式(比如數字、單詞以及字母或數字字符)提供了高級模式符號和特殊符號。
gawk就是使用ERE引擎來處理正則表達式。
9.2.定義BRE模式
最基本的BRE模式是匹配數據流中的文本字符.
9.2.1.普通文本
正則表達式對大小寫敏感.
正則表達式并不關心模式在數據流中出現的位置,也不在意模式出現了多少次。
只要能匹配文本字符串中任意位置的模式,正則表達式就會將該字符串傳回Linux工具。
在正則表達式中,空格和其他的字符沒有區別.如果在正則表達式中定義了空格,那么必須出現在數據流中。甚至可以創建匹配多個連續空格的正則表達式.
$ cat data1
This is a normal line of text.
This is a line with too many spaces.
$ sed -n '/ /p' data1
This is a line with too many spaces.
9.2.2.特殊字符
正則表達式中的一些字符具有特別的含義:
- .
- *
- []
- ^
- $
- {}
- \
- +
- ?
- |
- ()
不能在匹配普通文本的模式中單獨使用這些字符.
如果要將某個特殊字符視為普通字符,則必須將其轉義.使用特殊轉移字符反斜線(\)。
盡管正斜線 / 不屬于正則表達式的特殊字符,但如果出現在sed或gawk的正則表達式中,就會出現錯誤,所以正斜線也需要進行轉義.
9.2.3.錨點字符
默認情況下,當指定一個正則表達式模式時,只要模式出現在數據流中的任何地方,它就能匹配.有兩個特殊字符可以用來將模式鎖定在數據流中的行首或行尾。
錨定行首^
脫字符(^)可以指定位于數據流中文本行行首的模式。如果模式出現在行首之外的位置,則正則表達式無法匹配。
使用脫字符,就必須將其置于正則表達式之前
$ echo "The book store" | sed -n '/^book/p'
$
$ echo "Books are great" | sed -n '/^Book/p'
Books are great
如果將脫字符放到正則表達式開頭之外的位置,那么就跟普通字符一樣,沒有特殊含義
$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test
如果正則表達式模式中只有脫字符,就不必用反斜線來轉義。但如果在正則表達式中先指定脫字符,隨后還有其他文本,就必須在脫字符前用轉義字符.
$ echo "This is ^ a test" | sed -n '/^ a test/p'
$ echo "This is ^ a test" | sed -n '/\^ a test/p'
This is ^ a test
錨定行尾$
與在行首查找模式相反的情況是在行尾查找。特殊字符美元符號($)定義了行尾錨點。將這個特殊字符放在正則表達式之后則表示數據行必須以該模式結尾.
$ echo "This is a good book" | sed -n '/book$/p'
This is a good book
組合錨點
組合使用行首錨點和行尾錨點。
$ cat data4
this is a test of using both anchors
I said this is a test
this is a test
I'm sure this is a test.
$ sed -n '/^this is a test$/p' data4
this is a test
將這兩個錨點直接組合,之間不加任何文本,可以過濾掉數據流中的空行。
組合 刪除命令d就可以刪除掉文本中的空行.
$ 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.
9.2.4.點號字符.
點號字符可以匹配除換行符之外的任意單個字符。(空格也是字符,可以匹配)
點號字符必須匹配一個字符,如果在點號字符的位置沒有可匹配的字符,那么模式不成立。
$ 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.
9.2.5.字符組[]
想要限定要匹配的具體字符使用字符組.
可以在正則表達式中定義用來匹配某個位置的一組字符。如果字符組中的某個字符出現在了數據流中,那就能匹配該模式。
方括號 [] 用于定義字符組。
在不太確定某個字符的大小寫時非常適合使用字符組.
$ echo "Yes" | sed -n '/[Yy]es/p'
Yes
$ echo "yes" | sed -n '/[Yy]es/p'
yes
在一個正則表達式中可以使用多個字符組.
可以將多個字符組組合在一起,以檢查數字是否具備正確的格式.
$ cat data8
60633
46201
223001
4353
22203
$ sed -n '
> /^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p
> ' data8
60633
46201
22203
9.2.6.排除字符組
在正則表達式中,可以反轉字符組的作用:匹配字符組中沒有的字符。在字符組的開頭添加脫字符^:
$ sed -n '/[^ch]at/p' data6
This test is at line four.
即使是排除型,字符組仍必須匹配一個字符,以at為起始的行還是不能匹配模式!!!
8.2.7.區間
可以用單連字符在字符組中表示字符區間。只需指定區間的第一個字符、連字符以及區間的最后一個字符。
根據Linux系統使用的字符集,字符組會包括在此區間內的任意字符。
$ 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.
可以在單個字符組內指定多個不連續的區間:
$ sed -n '/[a-ch-m]at/p' data6
The cat is sleeping.
That is a very nice hat.
9.2.8.特殊字符組
BRE還提供了一些特殊的字符組,用來匹配特定類型的字符。
字符組 | 描述 |
---|---|
[[:alpha:]] | 匹配任意字母字符,無論大小寫 |
[[:alnum:]] | 匹配任意字母和數組字符,0-9、a-z、A-Z |
[[:blank:]] | 匹配空格和制表符 |
[[:digit:]] | 匹配0-9的數字 |
[[:lower:]] | 匹配a-z的字母 |
[[:upper:]] | 匹配A-Z的字母 |
[[:print:]] | 匹配任意可打印字符 |
[[:punct:]] | 匹配標點符號 |
[[:space:]] | 匹配任意空白字符:空格、制表符、換行符、分頁符、垂直制表符、回車符 |
特殊字符組在正則表達式中的用法和普通字符組一樣:
$ 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'
$ echo "This is, a test" | sed -n '/[[:punct:]]/p'
This is, a test
9.2.9.星號*
在字符后面放置星號,表明該字符必須在匹配模式的文本中出現0次或多次.
$ echo "ik" | sed -n '/ie*k/p'
ik
$ echo "iek" | sed -n '/ie*k/p'
iek
$ echo "ieek" | sed -n '/ie*k/p'
ieek
$ echo "ieeek" | sed -n '/ie*k/p'
ieeek
$ echo "ieeeek" | sed -n '/ie*k/p'
ieeeek
某些單詞在英美中不同,借助 星號可以匹配:
$ echo "I'm getting a color TV" | sed -n '/colou*r/p'
I'm getting a color TV
$ echo "I'm getting a colour TV" | sed -n '/colou*r/p'
I'm getting a colour TV
$
將點號字符和星號字符組合起來。這個組合能夠匹配任意數量的任意字符:
$ echo "this is a regular pattern expression" | sed -n '
> /regular.*expression/p'
this is a regular pattern expression
星號用于字符組時,指定可能在文本中出現0次或多次的字符組或字符區間:
$ echo "bt" | sed -n '/b[ae]*t/p'
bt
baaeeet
$ echo "baeeaeeat" | sed -n '/b[ae]*t/p'
baeeaeeat
$ echo "baakeeet" | sed -n '/b[ae]*t/p'
9.3.擴展正則表達式
POSIX ERE模式提供了一些可供Linux應用程序和工具使用的額外符號。gawk支持ERE模式,sed不支持。
可用于gawk腳本中的常見ERE模式符號。
9.3.1.問號?
問號表明字符可以出現0次或1次,不會匹配多次出現的該字符.用法與星號類似,可以作用與字符組.
$ echo "bt" | gawk '/be?t/{print $0}'
bt
$ echo "bet" | gawk '/be?t/{print $0}'
bet
$ echo "beet" | gawk '/be?t/{print $0}'
9.3.2.加號+
加號表明前面的字符可以出現1次或多次,必須至少出現1次。用法與星號類似,可以作用與字符組.
$ echo "bt" | gawk '/b[ae]+t/{print $0}'
$
$ echo "bat" | gawk '/b[ae]+t/{print $0}'
bat
$ echo "bet" | gawk '/b[ae]+t/{print $0}'
bet
$ echo "beat" | gawk '/b[ae]+t/{print $0}'
beat
$ echo "beet" | gawk '/b[ae]+t/{print $0}'
beet
$ echo "beeat" | gawk '/b[ae]+t/{print $0}'
beeat
9.3.3.花括號{}
ERE中的花括號允許為正則表達式指定具體的可重復次數,稱為區間。
可以用兩種格式來指定區間:
- m:正則表達式恰好出現m次。
- m, n:正則表達式至少出現m次,至多出現n次。
默認情況下,gawk也不識別正則表達式區間,必須指定gawk的命令行選項–re-interval。
$ 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}'
$
$ echo "bt" | gawk --re-interval '/be{1,2}t/{print $0}'
$
$ echo "bet" | gawk --re-interval '/be{1,2}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1,2}t/{print $0}'
beet
$ echo "beeet" | gawk --re-interval '/be{1,2}t/{print $0}'
$
$ echo "bt" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
$ echo "beet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
beet
$ echo "beeat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
9.3.4.豎線符號|
豎線符號允許在檢查數據流時,以邏輯OR方式指定正則表達式引擎要使用的兩個或多個模式。任何一個模式匹配了數據流文本,就視為匹配。
豎線符號兩側的子表達式可以采用正則表達式可用的任何模式符號(包括字符組)
$ 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}'
9.3.5.表達式分組
用圓括號對正則表達式進行分組。分組之后,每一組會被視為一個整體,可以像對普通字符一樣對該組應用特殊字符。
$ echo "Sat" | gawk '/Sat(urday)+/{print $0}'
$ echo "Saturday" | gawk '/Sat(urday)+/{print $0}'
Saturday
將分組和豎線符號結合起來創建可選的模式匹配組:
$ 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}'
$
9.4.實戰
9.4.1.目錄文件計數
對PATH環境變量中各個目錄所包含的文件數量進行統計.
PATH中的各個路徑由冒號分隔。要獲取可在腳本中使用的目錄列表,須用空格替換冒號.
$ echo $PATH | sed 's/:/ /g'
/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin
/usr/games /usr/local/games
分離出目錄之后,可以使用標準for語句遍歷每個目錄:
mypath=`echo $PATH | sed 's/:/ /g'`
for directory in $mypath
do
...
done
對于單個目錄,可以用ls命令列出其中的文件,再用另一個for語句來遍歷每個文件,對文件計數器增值。
$ cat countfiles
#!/bin/bash
# count number of files in your PATH
mypath=$(echo $PATH | sed 's/:/ /g')
count=0
for directory in $mypath
docheck=$(ls $directory)for item in $checkdocount=$[ $count + 1 ]doneecho "$directory - $count"count=0
done
$ ./countfiles /usr/local/sbin - 0
/usr/local/bin - 2
/usr/sbin - 213
/usr/bin - 1427
...
/usr/local/games - 0