shell編程基礎(五): 正則表達式及其使用

正則表達式

一、前情提要

  之前咱們用grep在一個文件中找出包含某些字符串的行,好比在頭文件中找出一個宏定義。其實grep還能夠找出符合某個模式(Pattern)的一類字符串。例如找出全部符合xxxxx@xxxx.xxx模式的字符串(也就是email地址),要求x字符能夠是字母、數字、下劃線、小數點或減號,email地址的每一部分能夠有一個或多個x字符,例如abc.d@ef.com、1_2@987-6.54,固然符合這個模式的不全是合法的email地址,但至少能夠作一次初步篩選,篩掉a.b、c@d等確定不是email地址的字符串。再好比,找出全部符合yyy.yyy.yyy.yyy模式的字符串(也就是IP地址),要求y是0-9的數字,IP地址的每一部分能夠有1-3個y字符。linux

若是要用grep查找一個模式,如何表示這個模式,這一類字符串,而不是一個特定的字符串呢?從這兩個簡單的例子能夠看出,要表示一個模式至少應該包含如下信息:git

  字符類(Character Class):如上例的x和y,它們在模式中表示一個字符,可是取值範圍是一類字符中的任意一個。正則表達式

  數量限定符(Quantifier): 郵件地址的每一部分能夠有一個或多個x字符,IP地址的每一部分能夠有1-3個y字符編程

各類字符類以及普通字符之間的位置關係:例如郵件地址分三部分,用普通字符@和.隔開,IP地址分四部分,用.隔開,每一部分均可以用字符類和數量限定符描述。centos

爲了表示位置關係,還有位置限定符(Anchor)的概念,將在下面介紹。less

規定一些特殊語法表示字符類、數量限定符和位置關係,而後用這些特殊語法和普通字符一塊兒表示一個模式,這就是正則表達式(Regular Expression)。編程語言

例如email地址的正則表達式能夠寫成[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+.[a-zA-Z0-9_.-]+,IP地址的正則表達式能夠寫成[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}。工具

等下介紹正則表達式的語法,咱們先看看正則表達式在grep中怎麼用。例若有這樣一個文本文件testgrep:學習

[root@VM_0_5_centos test]# vi testgrep.file 
[root@VM_0_5_centos test]# cat testgrep.file 
192.168.13.108
123.5254.045.678
abcde52s
198.23.233.342
1233.232.232.4

查找其中包含IP地址的行:網站

注:一、egrep至關於grep -E,表示採用Extended正則表達式語法。另外還有fgrep命令,至關於grep -F,表示只搜索固定字符串而不搜索正則表達式模式,不會按正則表達式的語法解釋後面的參數。

二、正則表達式參數用單引號括起來了,由於正則表達式中用到的不少特殊字符在Shell中也有特殊含義(例如\),只有用單引號括起來才能保證這些字符原封不動地傳給grep命令,而不會被Shell解釋掉。

grep的正則表達式有Basic和Extended兩種規範:
一、grep正則表達式的Extended規範在基本語法中介紹;
二、Basic規範也有Extended規範的這些語法,只是字符?+{}|()應解釋爲普通字符,要表示上述特殊含義則須要加\轉義。若是用grep而不是egrep,而且不加-E參數,則應該遵守Basic規範來寫正則表達式。

問:192.168.13.108符合上述模式,由三個.隔開的四段組成,每段都是1到3個數字,因此這一行被找出來了,可爲何1233.232.232.4也被找出來了呢?

答:由於grep找的是包含某一模式的行,這一行包含一個符合模式的字符串233.232.232.4。相反,123.5254.045.678這一行不包含符合模式的字符串,因此不會被找出來。

  grep是一種查找過濾工具,正則表達式在grep中用來查找符合模式的字符串。其實正則表達式還有一個重要的應用是驗證用戶輸入是否合法,例如用戶經過網頁表單提交本身的email地址,就須要用程序驗證一下是否是合法的email地址,這個工做能夠在網頁的Javascript中作,也能夠在網站後臺的程序中作,例如PHP、Perl、Python、Ruby、Java或C,全部這些語言都支持正則表達式,能夠說,目前不支持正則表達式的編程語言實在不多見。除了編程語言以外,不少UNIX命令和工具也都支持正則表達式,例如grep、vi、sed、awk、emacs等等。「正則表達式」就像「變量」同樣,它是一個普遍的概念,而不是某一種工具或編程語言的特性。

二、基本語法

  咱們知道C的變量和Shell腳本變量的定義和使用方法很不相同,表達能力也不相同,C的變量有各類類型,而Shell腳本變量都是字符串。一樣道理,各類工具和編程語言所使用的正則表達式規範的語法並不相同,表達能力也各不相同,有的正則表達式規範引入不少擴展,能表達更復雜的模式,但各類正則表達式規範的基本概念都是相通的。本節介紹egrep(1)所使用的正則表達式,它大體上符合POSIX正則表達式規範,詳見regex(7)(看這個man page對你的英文絕對是很好的鍛鍊)。但願讀者仿照上一節的例子,一邊學習語法,一邊用egrep命令作實驗。

字符類:

字符 含義 舉例
. 匹配任意一個字符  abc.能夠匹配abcd、abc9等
[] 匹配括號中的任意一個字符 [abc]d能夠匹配ad、bd或cd
- 在[]括號內表示字符範圍  [0-9a-fA-F]能夠匹配一位十六進制數字
^ 位於[]括號內的開頭,匹配除括號中的字符以外的任意一個字符  [^xy]匹配除xy以外的任一字符,所以[^xy]1能夠匹配a一、b1但不匹配x一、y1
[[:xxx:]] grep工具預約義的一些命名字符類  [[:alpha:]]匹配一個字母,[[:digit:]]匹配一個數字

數量限定符:

字符 含義 舉例
?
緊跟在它前面的單元應匹配零次或一次
[0-9]?\.[0-9]匹配0.0、2.三、.5等,因爲.在正則表達式中是一個特殊字符,因此須要用\轉義一下,取字面值
+
緊跟在它前面的單元應匹配一次或屢次   
[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+匹配email地址
*
緊跟在它前面的單元應匹配零次或屢次
[0-9][0-9]*匹配至少一位數字,等價於[0-9]+,[a-zA-Z_]+[a-zA-Z_0-9]*匹配C語言的標識符
{N}
緊跟在它前面的單元應精確匹配N次  
[1-9][0-9]{2}匹配從100到999的整數
{n,}
緊跟在它前面的單元應匹配至少N次   
[1-9][0-9]{2,}匹配三位以上(含三位)的整數
{,M}
緊跟在它前面的單元應匹配最多M次 
[0-9]{,1}至關於[0-9]?
{N,M}
緊跟在它前面的單元應匹配至少N次,最多M次  
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}匹配IP地址

再次注意grep找的是包含某一模式的行,而不是徹底匹配某一模式的行。再舉個例子,若是文本文件的內容是:

[root@VM_0_5_centos test]# vi testfile.txt
[root@VM_0_5_centos test]# cat testfile.txt 
acaabc
caad
efg
sdcasd
sda

查找a*這個模式的結果是三行都被找出來了:

注:a匹配0個或多個a,而第三行包含0個a,因此也包含了這一模式。單獨用a這樣的正則表達式作查找沒什麼意義,通常是把a*做爲正則表達式的一部分來用。

位置限定符:

字符 含義 舉例
^
匹配行首的位置
^Content匹配位於一行開頭的Content
$
匹配行末的位置       
 ;$匹配位於一行結尾的;號,^$匹配空行
\<
匹配單詞開頭的位置  
\<th匹配... this,但不匹配ethernet、tenth
\>
匹配單詞結尾的位置    
p\>匹配leap ...,但不匹配parent、sleepy
\b
匹配單詞開頭或結尾的位置     
\bat\b匹配... at ...,但不匹配cat、atexit、batch
\B
匹配非單詞開頭和結尾的位置  
 \Bat\B匹配battery,但不匹配... attend、hat ...

位置限定符能夠幫助grep更準確地查找,例如上一節咱們用[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}查找IP地址,找到這兩行:

192.168.13.108
198.23.233.342
1233.232.232.4

若是用^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$查找,就能夠把1233.232.232.4這一行過濾掉了。

其它特殊字符:

字符 含義 舉例
\
轉義字符,普通字符轉義爲特殊字符,特殊字符轉義爲普通字符 
普通字符<寫成\<表示單詞開頭的位置,特殊字符.寫成\.以及\寫成\\就看成普通字符來匹配
()
 將正則表達式的一部分括起來組成一個單元,能夠對整個單元使用數量限定符
([0-9]{1,3}\.){3}[0-9]{1,3}匹配IP地址
|
 鏈接兩個子表達式,表示或的關係
n(o|either)匹配no或neither

以上介紹的是grep正則表達式的Extended規範,Basic規範也有這些語法,只是字符?+{}|()應解釋爲普通字符,要表示上述特殊含義則須要加\轉義。若是用grep而不是egrep,而且不加-E參數,則應該遵守Basic規範來寫正則表達式。

三、grep

1.做用

Linux系統中grep命令是一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹 配的行打印出來。grep全稱是Global Regular Expression Print,表示全局正則表達式版本,它的使用權限是全部用戶。

rep家族包括grep、egrep和fgrep:
egrep和fgrep的命令只跟grep有很小不一樣。
egrep是grep的擴展,支持更多的re元字符;
fgrep就是fixed grep或fast grep,它們把全部的字母都看做單詞,也就是說,正則表達式中的元字符表示回其自身的字面意義,再也不特殊。
linux使用GNU版本的grep。它功能更強,能夠經過-G、-E、-F命令行選項來使用egrep和fgrep的功能。

2.格式

grep [options]

3.主要參數

grep --help

[options]主要參數:
-c:只輸出匹配行的計數。
-i:不區分大小寫。
-h:查詢多文件時不顯示文件名。
-l:查詢多文件時只輸出包含匹配字符的文件名。
-n:顯示匹配行及行號。
-s:不顯示不存在或無匹配文本的錯誤信息。
-v:顯示不包含匹配文本的全部行。
--color=auto :能夠將找到的關鍵詞部分加上顏色的顯示。

pattern正則表達式主要參數:(pattern部分最好用雙引號)

\      忽略正則表達式中特殊字符的原有含義。
^      匹配正則表達式的開始行。
$      匹配正則表達式的結束行。
\<     從匹配正則表達 式的行開始。
\>     到匹配正則表達式的行結束。
[ ]     單個字符,如[A]即A符合要求 。
[ - ]   範圍,如[A-Z],即A、B、C一直到Z都符合要求 。
.      全部的單個字符。
*      有字符,長度能夠爲0。

4.grep命令使用簡單實例

顯示全部以d開頭的文件中包含 test的行;
[root@VM_0_5_centos test]# grep 「test」 d*

顯示在aa,bb,cc文件中匹配test的行(./*表示當前目錄下的全部文件);
[root@VM_0_5_centos test]# grep ‘test’ aa bb cc
[root@VM_0_5_centos test]# egrep "sda" ./* ./test:sda ./testfile.txt:sda ./testsd:sdadf [root@VM_0_5_centos test]# egrep "sda" ./* -n ./test:2:sda ./testfile.txt:5:sda ./testsd:2:sdadf [root@VM_0_5_centos test]# egrep "sda" ./* -c ./test:1 ./testfile.txt:1 ./testgrep.file:0 ./testsd:1 ./tfun.sh:0

顯示全部包含每一個字符串至少有5個連續小寫字符的字符串的行;
[root@VM_0_5_centos test]# grep 「[a-z]\{5\}」 test
[root@VM_0_5_centos test]# egrep 「[a-z]{5}」 test

若是asd被匹配,則s就被存儲到內存中,並標記爲1,而後搜索任意個字符(.*),這些字符後面緊跟着另一個s(\1),找到就顯示該行。若是用egrep或grep -E,就不用」\」號進行轉義,直接寫成’a(s)d.*\1′就能夠了;
[root@VM_0_5_centos test]# grep 「a\(s\)d.*\1」 test

5.grep命令使用複雜實例

明確要求搜索子目錄:

grep -r

或忽略子目錄:

grep -d skip

若是有不少輸出時,您能夠經過管道將其轉到’less’上閱讀:

IP地址的正則表達式能夠寫成[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}。
grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' testgrep.file | less

這樣,您就能夠更方便地閱讀。

注意:您必需提供一個文件過濾方式(搜索所有文件的話用 *)。若是您忘了,’grep’會一直等着,直到該程序被中斷。若是您遇到了這樣的狀況,按 ,而後再試。

下面還有一些有意思的命令行參數:

grep -i pattern files  //不區分大小寫地搜索。默認狀況區分大小寫,
grep -l pattern files  //只列出匹配的文件名,
grep -L pattern files  //列出不匹配的文件名,
grep -w pattern files  //只匹配整個單詞,而不是字符串的一部分(如匹配’magic’,而不是’magical’),
grep -C number pattern files//匹配的上下文分別顯示[number]行,
grep pattern1 | pattern2 files //顯示匹配 pattern1 或 pattern2 的行,
例如:
grep "abc\|xyz" testfile    表示過濾包含abc或xyz的行
grep pattern1 files | grep pattern2 //顯示既匹配 pattern1 又匹配 pattern2 的行。
grep -n pattern files  //便可顯示行號信息
grep -c pattern files  //便可查找總行數

這裏還有些用於搜索的特殊符號:

\< 和 \>     分別標註單詞的開始與結尾
例如:
grep man *     會匹配 ‘Batman’、’manic’、’man’等;
grep ‘\<man’ *     會匹配’manic’和’man’,但不是’Batman’;
grep ‘\<man\>’     只匹配’man’,而不是’Batman’或’manic’等其餘的字符串。
‘^’    指匹配的字符串在行首;
‘$’    指匹配的字符串在行尾;
例如:
[root@VM_0_5_centos test]# cat testfile.txt 
acaabc
caad
efg
sdcasd
sda
[root@VM_0_5_centos test]# grep '^a' testfile.txt 
acaabc
[root@VM_0_5_centos test]# grep -E '^a' testfile.txt 
acaabc
[root@VM_0_5_centos test]# grep -E 'a$' testfile.txt 
sda
相關文章
相關標籤/搜索