grep用法好简单,看bird兄教你玩转grep

前言:什麼是正規表示法

約略瞭解了 Linux 的基本指令 (BASH) 並且熟悉了 vim 之後,相信你對於敲擊鍵盤的打字與指令下達比較不陌生了吧? 接下來,底下要開始介紹一個很重要的觀念,那就是所謂的『正規表示法 (Regular Expression)』囉!


小標題的圖示什麼是正規表示法

任何一個有經驗的系統管理員,都會告訴你:『正規表示法真是挺重要的!』 為什麼很重要呢?因為日常生活就使用的到啊!舉個例子來說, 在你日常使用 vim 作文書處理或程式撰寫時使用到的『搜尋/取代』等等的功能, 這些舉動要作的漂亮,就得要配合正規表示法來處理囉!

簡單的說,正規表示法就是處理字串的方法,他是以行為單位來進行字串的處理行為, 正規表示法透過一些特殊符號的輔助,可以讓使用者輕易的達到『搜尋/刪除/取代』某特定字串的處理程序!

舉例來說,我只想找到 VBird(前面兩個大寫字元) 或 Vbird(僅有一個大寫字元) 這個字樣,但是不要其他的字串 (例如 VBIRD, vbird 等不需要),該如何辦理?如果在沒有正規表示法的環境中(例如 MS word),你或許就得要使用忽略大小寫的辦法, 或者是分別以 VBird 及 Vbird 搜尋兩遍。但是,忽略大小寫可能會搜尋到 VBIRD/vbird/VbIrD 等等的不需要的字串而造成困擾。

再舉個系統常見的例子好了,假設妳發現系統在開機的時候,老是會出現一個關於 mail 程式的錯誤, 而開機過程的相關程序都是在 /etc/init.d/ 底下,也就是說,在該目錄底下的某個檔案內具有 mail 這個關鍵字,你想要將該檔案捉出來進行查詢修改的動作。此時你怎麼找出來含有這個關鍵字的檔案? 你當然可以一個檔案一個檔案的開啟,然後去搜尋 mail 這個關鍵字,只是.....該目錄底下的檔案可能不止 100 個說~ 如果瞭解正規表示法的相關技巧,那麼只要一行指令就找出來啦:『grep 'mail' /etc/init.d/*』 那個 grep 就是支援正規表示法的工具程式之一!如何~很簡單吧!

談到這裡就得要進一步說明了,正規表示法基本上是一種『表示法』, 只要工具程式支援這種表示法,那麼該工具程式就可以用來作為正規表示法的字串處理之用。 例如 vi, grep, awk ,sed 等等工具,因為她們有支援正規表示法, 所以,這些工具就可以使用正規表示法的特殊字元來進行字串的處理。但例如 cp, ls 等指令並未支援正規表示法, 所以就只能使用 bash 自己本身的萬用字元而已。


小標題的圖示正規表示法對於系統管理員的用途

那麼為何我需要學習正規表示法呢?對於一般使用者來說,由於使用到正規表示法的機會可能不怎麼多, 因此感受不到他的魅力,不過,對於身為系統管理員的你來說,正規表示法則是一個『不可不學的好東西!』 怎麼說呢?由於系統如果在繁忙的情況之下,每天產生的訊息資訊會多到你無法想像的地步, 而我們也都知道,系統的『錯誤訊息登錄檔案 (第十九章)』 的內容記載了系統產生的所有訊息,當然,這包含你的系統是否被『入侵』的記錄資料。

但是系統的資料量太大了,要身為系統管理員的你每天去看這麼多的訊息資料, 從千百行的資料裡面找出一行有問題的訊息,呵呵~光是用肉眼去看,想不瘋掉都很難! 這個時候,我們就可以透過『正規表示法』的功能,將這些登錄的資訊進行處理, 僅取出『有問題』的資訊來進行分析,哈哈!如此一來,你的系統管理工作將會 『快樂得不得了』啊!當然,正規表示法的優點還不止於此,等你有一定程度的瞭解之後,你會愛上他喔!


小標題的圖示正規表示法的廣泛用途

正規表示法除了可以讓系統管理員管理主機更為便利之外,事實上,由於正規表示法強大的字串處理能力, 目前一堆軟體都支援正規表示法呢!最常見的就是『郵件伺服器』啦!

如果你留意網際網路上的消息,那麼應該不難發現,目前造成網路大塞車的主因之一就是『垃圾/廣告信件』了, 而如果我們可以在伺服器端,就將這些問題郵件剔除的話,用戶端就會減少很多不必要的頻寬耗損了。 那麼如何剔除廣告信件呢?由於廣告信件幾乎都有一定的標題或者是內容,因此, 只要每次有來信時,都先將來信的標題與內容進行特殊字串的比對,發現有不良信件就予以剔除! 嘿!這個工作怎麼達到啊?就使用正規表示法啊!目前兩大郵件伺服器軟體 sendmail 與 postfix 以及支援郵件伺服器的相關分析軟體,都支援正規表示法的比對功能!

當然還不止於此啦,很多的伺服器軟體都支援正規表示法呢!當然, 雖然各家軟體都支援他,不過,這些『字串』的比對還是需要系統管理員來加入比對規則的, 所以啦!身為系統管理員的你,為了自身的工作以及用戶端的需求, 正規表示法實在是很需要也很值得學習的一項工具呢!


小標題的圖示正規表示法與 Shell 在 Linux 當中的角色定位

說實在的,我們在學數學的時候,一個很重要、但是粉難的東西是一定要『背』的, 那就是九九乘法表,背成功了之後,未來在數學應用的路途上,真是一帆風順啊! 這個九九乘法表我們在小學的時候幾乎背了一整年才背下來,並不是這麼好背的呢! 但他卻是基礎當中的基礎!你現在一定受惠相當的多呢 ^_^!

而我們談到的這個正規表示法,與前一章的 BASH 就有點像是數學的九九乘法表一樣,是 Linux 基礎當中的基礎,雖然也是最難的部分, 不過,如果學成了之後,一定是『大大的有幫助』的!這就好像是金庸小說裡面的學武難關:任督二脈! 打通任督二脈之後,武功立刻成倍成長!所以啦, 不論是對於系統的認識與系統的管理部分,他都有很棒的輔助啊!請好好的學習這個基礎吧! ^_^


小標題的圖示延伸的正規表示法

唔!正規表示法還有分喔?沒錯喔!正規表示法的字串表示方式依照不同的嚴謹度而分為: 基礎正規表示法與延伸正規表示法。延伸型正規表示法除了簡單的一組字串處理之外,還可以作群組的字串處理, 例如進行搜尋 VBird 或 netman 或 lman 的搜尋,注意,是『或(or)』而不是『和(and)』的處理, 此時就需要延伸正規表示法的幫助啦!藉由特殊的『 ( 』與『 | 』等字元的協助, 就能夠達到這樣的目的!不過,我們在這裡主力僅是介紹最基礎的基礎正規表示法而已啦!好啦!清清腦門,咱們用功去囉!


表示法時,老想著要將這兩者歸納在一起,結果就是...錯誤認知一大堆~ 所以才會建議您學習本章先忘記萬用字元再來學習吧!鳥哥的圖示



-----------前面这些都是废话,咳咳,现在正是开始!微笑-------


大標題的圖示基礎正規表示法

既然正規表示法是處理字串的一種表示方式,那麼對字元排序有影響的語系資料就會對正規表示法的結果有影響! 此外,正規表示法也需要支援工具程式來輔助才行!所以,我們這裡就先介紹一個最簡單的字串擷取功能的工具程式,那就是 grep 囉! 前一章已經介紹過 grep 的相關選項與參數,本章著重在較進階的 grep 選項說明囉! 介紹完 grep 的功能之後,就進入正規表示法的特殊字符的處理能力了。


小標題的圖示語系對正規表示法的影響

為什麼語系的資料會影響到正規表示法的輸出結果呢?我們在第零章計算機概論的文字編碼系統裡面談到,檔案其實記錄的僅有 0 與 1,我們看到的字元文字與數字都是透過編碼表轉換來的。由於不同語系的編碼資料並不相同,所以就會造成資料擷取結果的差異了。 舉例來說,在英文大小寫的編碼順序中,zh_TW.big5 及 C 這兩種語系的輸出結果分別如下:

  • LANG=C     時:0 1 2 3 4 ... A B C D ... Z a b c d ...z
  • LANG=zh_TW 時:0 1 2 3 4 ... a A b B c C d D ... z Z

上面的順序是編碼的順序,我們可以很清楚的發現這兩種語系明顯就是不一樣!如果你想要擷取大寫字元而使用 [A-Z] 時, 會發現 LANG=C 確實可以僅捉到大寫字元 (因為是連續的) ,但是如果 LANG=zh_TW.big5 時,就會發現到, 連同小寫的 b-z 也會被擷取出來!因為就編碼的順序來看, big5 語系可以擷取到『 A b B c C ... z Z 』這一堆字元哩! 所以,使用正規表示法時,需要特別留意當時環境的語系為何, 否則可能會發現與別人不相同的擷取結果喔!

由於一般我們在練習正規表示法時,使用的是相容於 POSIX 的標準,因此就使用『 C 』這個語系(註1)! 因此,底下的很多練習都是使用『 LANG=C 』這個語系資料來進行的喔! 另外,為了要避免這樣編碼所造成的英文與數字的擷取問題,因此有些特殊的符號我們得要瞭解一下的! 這些符號主要有底下這些意義:(註1)

特殊符號代表意義
[:alnum:]代表英文大小寫字元及數字,亦即 0-9, A-Z, a-z
[:alpha:]代表任何英文大小寫字元,亦即 A-Z, a-z
[:blank:]代表空白鍵與 [Tab] 按鍵兩者
[:cntrl:]代表鍵盤上面的控制按鍵,亦即包括 CR, LF, Tab, Del.. 等等
[:digit:]代表數字而已,亦即 0-9
[:graph:]除了空白字元 (空白鍵與 [Tab] 按鍵) 外的其他所有按鍵
[:lower:]代表小寫字元,亦即 a-z
[:print:]代表任何可以被列印出來的字元
[:punct:]代表標點符號 (punctuation symbol),亦即:" ' ? ! ; : # $...
[:upper:]代表大寫字元,亦即 A-Z
[:space:]任何會產生空白的字元,包括空白鍵, [Tab], CR 等等
[:xdigit:]代表 16 進位的數字類型,因此包括: 0-9, A-F, a-f 的數字與字元

尤其上表中的[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 這幾個一定要知道代表什麼意思,因為他要比 a-z 或 A-Z 的用途要確定的很!好了,底下就讓我們開始來玩玩進階版的 grep 吧!


小標題的圖示grep 的一些進階選項

我們在第十一章 BASH 裡面的 grep 談論過一些基礎用法, 但其實 grep 還有不少的進階用法喔!底下我們僅列出較進階的 grep 選項與參數給大家參考, 基礎的 grep 用法請參考前一章的說明囉!

[root@www ~]# grep [-A] [-B] [--color=auto] '搜尋字串' filename
選項與參數:
-A :後面可加數字,為 after 的意思,除了列出該行外,後續的 n 行也列出來;
-B :後面可加數字,為 befer 的意思,除了列出該行外,前面的 n 行也列出來;
--color=auto 可將正確的那個擷取資料列出顏色

範例一:用 dmesg 列出核心訊息,再以 grep 找出內含 eth 那行
[root@www ~]# dmesg | grep 'eth'
eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
eth0:  Identified 8139 chip type 'RTL-8139C'
eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
eth0: no IPv6 routers present
# dmesg 可列出核心產生的訊息!透過 grep 來擷取網路卡相關資訊 (eth) ,
# 就可發現如上資訊。不過沒有行號與特殊顏色顯示!看看下個範例吧!

範例二:承上題,要將捉到的關鍵字顯色,且加上行號來表示:
[root@www ~]# dmesg | grep -n --color=auto 'eth'
247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
248:eth0:  Identified 8139 chip type 'RTL-8139C'
294:eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
305:eth0: no IPv6 routers present
# 你會發現除了 eth 會有特殊顏色來表示之外,最前面還有行號喔!

範例三:承上題,在關鍵字所在行的前兩行與後三行也一起捉出來顯示
[root@www ~]# dmesg | grep -n -A3 -B2 --color=auto 'eth'
245-PCI: setting IRQ 10 as level-triggered
246-ACPI: PCI Interrupt 0000:00:0e.0[A] -> Link [LNKB] ...
247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
248:eth0:  Identified 8139 chip type 'RTL-8139C'
249-input: PC Speaker as /class/input/input2
250-ACPI: PCI Interrupt 0000:00:01.4[B] -> Link [LNKB] ...
251-hdb: ATAPI 48X DVD-ROM DVD-R-RAM CD-R/RW drive, 2048kB Cache, UDMA(66)
# 如上所示,你會發現關鍵字 247 所在的前兩行及 248 後三行也都被顯示出來!
# 這樣可以讓你將關鍵字前後資料捉出來進行分析啦!

grep 是一個很常見也很常用的指令,他最重要的功能就是進行字串資料的比對,然後將符合使用者需求的字串列印出來。 需要說明的是『grep 在資料中查尋一個字串時,是以 "整行" 為單位來進行資料的擷取的!』也就是說,假如一個檔案內有 10 行,其中有兩行具有你所搜尋的字串,則將那兩行顯示在螢幕上,其他的就丟棄了!

在關鍵字的顯示方面,grep 可以使用 --color=auto 來將關鍵字部分使用顏色顯示。 這可是個很不錯的功能啊!但是如果每次使用 grep 都得要自行加上 --color=auto 又顯的很麻煩~ 此時那個好用的 alias 就得來處理一下啦!你可以在 ~/.bashrc 內加上這行:『alias grep='grep --color=auto'』再以『 source ~/.bashrc 』來立即生效即可喔! 這樣每次執行 grep 他都會自動幫你加上顏色顯示啦!


小標題的圖示基礎正規表示法練習

要瞭解正規表示法最簡單的方法就是由實際練習去感受啦!所以在彙整正規表示法特殊符號前, 我們先以底下這個檔案的內容來進行正規表示法的理解吧!先說明一下,底下的練習大前提是:

  • 語系已經使用『 export LANG=C 』的設定值;
  • grep 已經使用 alias 設定成為『 grep --color=auto 』

至於本章的練習用檔案請由底下的連結來下載。需要特別注意的是,底下這個檔案是鳥哥在 MS Windows 系統下編輯的, 並且已經特殊處理過,因此,他雖然是純文字檔,但是內含一些 Windows 系統下的軟體常常自行加入的一些特殊字元,例如斷行字元 (^M) 就是一例! 所以,你可以直接將底下的文字以 vi 儲存成 regular_express.txt 這個檔案, 不過,還是比較建議直接點底下的連結:

http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

如果你的 Linux 可以直接連上 Internet 的話,那麼使用如下的指令來捉取即可:

wget http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

至於這個檔案的內容如下:

[root@www ~]# vi regular_express.txt
"Open Source" is a good mechanism to develop programs.
apple is my favorite food.
Football game is not use feet only.
this dress doesn't fit me.
However, this dress is about $ 3183 dollars.^M
GNU is free air not free beer.^M
Her hair is very beauty.^M
I can't finish the test.^M
Oh! The soup taste good.^M
motorcycle is cheap than car.
This window is clear.
the symbol '*' is represented as start.
Oh!     My god!
The gd software is a library for drafting programs.^M
You are the best is mean you are the no. 1.
The world <Happy> is the same with "glad".
I like dog.
google is the best tools for search keyword.
goooooogle yes!
go! go! Let's go.
# I am VBird

這檔案共有 22 行,最底下一行為空白行!現在開始我們一個案例一個案例的來介紹吧!


  • 例題一、搜尋特定字串

搜尋特定字串很簡單吧?假設我們要從剛剛的檔案當中取得 the 這個特定字串,最簡單的方式就是這樣:

[root@www ~]# grep -n 'the' regular_express.txt
8:I can't finish the test.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.

那如果想要『反向選擇』呢?也就是說,當該行沒有 'the' 這個字串時才顯示在螢幕上,那就直接使用:

[root@www ~]# grep -vn 'the' regular_express.txt

你會發現,螢幕上出現的行列為除了 8,12,15,16,18 五行之外的其他行列! 接下來,如果你想要取得不論大小寫的 the 這個字串,則:

[root@www ~]# grep -in 'the' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.
12:the symbol '*' is represented as start.
14:The gd software is a library for drafting programs.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.

除了多兩行 (9, 14行) 之外,第 16 行也多了一個 The 的關鍵字被擷取到喔!


  • 例題二、利用中括號 [] 來搜尋集合字元

如果我想要搜尋 test 或 taste 這兩個單字時,可以發現到,其實她們有共通的 't?st' 存在~這個時候,我可以這樣來搜尋:

[root@www ~]# grep -n 't[ae]st' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.

瞭解了吧?其實 [] 裡面不論有幾個字元,他都謹代表某『一個』字元, 所以,上面的例子說明了,我需要的字串是『tast』或『test』兩個字串而已! 而如果想要搜尋到有 oo 的字元時,則使用:

[root@www ~]# grep -n 'oo' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

但是,如果我不想要 oo 前面有 g 的話呢?此時,可以利用在集合字元的反向選擇 [^] 來達成:

[root@www ~]# grep -n '[^g]oo' regular_express.txt
2:apple is my favorite food.
3:Football game is not use feet only.
18:google is the best tools for search keyword.
19:goooooogle yes!

意思就是說,我需要的是 oo ,但是 oo 前面不能是 g 就是了!仔細比較上面兩個表格,妳會發現,第 1,9 行不見了,因為 oo 前面出現了 g 所致!第 2,3 行沒有疑問,因為 foo 與 Foo 均可被接受!但是第 18 行明明有 google 的 goo 啊~別忘記了,因為該行後面出現了 tool 的 too 啊!所以該行也被列出來~ 也就是說, 18 行裡面雖然出現了我們所不要的項目 (goo) 但是由於有需要的項目 (too) , 因此,是符合字串搜尋的喔!

至於第 19 行,同樣的,因為 goooooogle 裡面的 oo 前面可能是 o ,例如: go(ooo)oogle ,所以,這一行也是符合需求的!

再來,假設我 oo 前面不想要有小寫字元,所以,我可以這樣寫 [^abcd....z]oo , 但是這樣似乎不怎麼方便,由於小寫字元的 ASCII 上編碼的順序是連續的, 因此,我們可以將之簡化為底下這樣:

[root@www ~]# grep -n '[^a-z]oo' regular_express.txt
3:Football game is not use feet only.

也就是說,當我們在一組集合字元中,如果該字元組是連續的,例如大寫英文/小寫英文/數字等等, 就可以使用[a-z],[A-Z],[0-9]等方式來書寫,那麼如果我們的要求字串是數字與英文呢? 呵呵!就將他全部寫在一起,變成:[a-zA-Z0-9]。例如,我們要取得有數字的那一行,就這樣:

[root@www ~]# grep -n '[0-9]' regular_express.txt
5:However, this dress is about $ 3183 dollars.
15:You are the best is mean you are the no. 1.

但由於考慮到語系對於編碼順序的影響,因此除了連續編碼使用減號『 - 』之外, 你也可以使用如下的方法來取得前面兩個測試的結果:

[root@www ~]# grep -n '[^[:lower:]]oo' regular_express.txt
# 那個 [:lower:] 代表的就是 a-z 的意思!請參考前兩小節的說明表格

[root@www ~]# grep -n '[[:digit:]]' regular_express.txt

這樣對於 [] 以及 [^] 以及 [] 當中的 - ,還有關於前面表格提到的特殊關鍵字有瞭解了嗎?^_^!


  • 例題三、行首與行尾字元 ^ $

我們在例題一當中,可以查詢到一行字串裡面有 the 的,那如果我想要讓 the 只在行首列出呢? 這個時候就得要使用定位字元了!我們可以這樣做:

[root@www ~]# grep -n '^the' regular_express.txt
12:the symbol '*' is represented as start.

此時,就只剩下第 12 行,因為只有第 12 行的行首是 the 開頭啊~此外, 如果我想要開頭是小寫字元的那一行就列出呢?可以這樣:

[root@www ~]# grep -n '^[a-z]' regular_express.txt
2:apple is my favorite food.
4:this dress doesn't fit me.
10:motorcycle is cheap than car.
12:the symbol '*' is represented as start.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

你可以發現我們可以捉到第一個字元都不是大寫的!只不過 grep 列出的關鍵字部分不只有第一個字元, grep 是列出一整個字 (word) 說!同樣的,上面的指令也可以用如下的方式來取代的:

[root@www ~]# grep -n '^[[:lower:]]' regular_express.txt

好!那如果我不想要開頭是英文字母,則可以是這樣:

[root@www ~]# grep -n '^[^a-zA-Z]' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
21:# I am VBird
# 指令也可以是: grep -n '^[^[:alpha:]]' regular_express.txt

注意到了吧?那個 ^ 符號,在字元集合符號(括號[])之內與之外是不同的! 在 [] 內代表『反向選擇』,在 [] 之外則代表定位在行首的意義!要分清楚喔! 反過來思考,那如果我想要找出來,行尾結束為小數點 (.) 的那一行,該如何處理:

[root@www ~]# grep -n '\.$' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
4:this dress doesn't fit me.
10:motorcycle is cheap than car.
11:This window is clear.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
17:I like dog.
18:google is the best tools for search keyword.
20:go! go! Let's go.

特別注意到,因為小數點具有其他意義(底下會介紹),所以必須要使用跳脫字元(\)來加以解除其特殊意義! 不過,你或許會覺得奇怪,但是第 5~9 行最後面也是 . 啊~怎麼無法列印出來? 這裡就牽涉到 Windows 平台的軟體對於斷行字元的判斷問題了!我們使用 cat -A 將第五行拿出來看, 你會發現:

[root@www ~]# cat -An regular_express.txt | head -n 10 | tail -n 6
     5  However, this dress is about $ 3183 dollars.^M$
     6  GNU is free air not free beer.^M$
     7  Her hair is very beauty.^M$
     8  I can't finish the test.^M$
     9  Oh! The soup taste good.^M$
    10  motorcycle is cheap than car.$

我們在第十章內談到過斷行字元在 Linux 與 Windows 上的差異, 在上面的表格中我們可以發現 5~9 行為 Windows 的斷行字元 (^M$) ,而正常的 Linux 應該僅有第 10 行顯示的那樣 ($) 。所以囉,那個 . 自然就不是緊接在 $ 之前喔!也就捉不到 5~9 行了!這樣可以瞭解 ^ 與 $ 的意義嗎? 好了,先不要看底下的解答,自己想一想,那麼如果我想要找出來,哪一行是『空白行』, 也就是說,該行並沒有輸入任何資料,該如何搜尋?

[root@www ~]# grep -n '^$' regular_express.txt
22:

因為只有行首跟行尾 (^$),所以,這樣就可以找出空白行啦!再來,假設你已經知道在一個程式腳本 (shell script) 或者是設定檔當中,空白行與開頭為 # 的那一行是註解,因此如果你要將資料列出給別人參考時, 可以將這些資料省略掉以節省保貴的紙張,那麼你可以怎麼作呢? 我們以 /etc/syslog.conf 這個檔案來作範例,你可以自行參考一下輸出的結果:

[root@www ~]# cat -n /etc/syslog.conf
# 在 CentOS 中,結果可以發現有 33 行的輸出,很多空白行與 # 開頭

[root@www ~]# grep -v '^$' /etc/syslog.conf | grep -v '^#'
# 結果僅有 10 行,其中第一個『 -v '^$' 』代表『不要空白行』,
# 第二個『 -v '^#' 』代表『不要開頭是 # 的那行』喔!

是否節省很多版面啊?


  • 例題四、任意一個字元 . 與重複字元 *

第十一章 bash 當中,我們知道萬用字元 * 可以用來代表任意(0或多個)字元, 但是正規表示法並不是萬用字元,兩者之間是不相同的! 至於正規表示法當中的『 . 』則代表『絕對有一個任意字元』的意思!這兩個符號在正規表示法的意義如下:

  • . (小數點):代表『一定有一個任意字元』的意思;
  • * (星星號):代表『重複前一個字元, 0 到無窮多次』的意思,為組合形態

這樣講不好懂,我們直接做個練習吧!假設我需要找出 g??d 的字串,亦即共有四個字元, 起頭是 g 而結束是 d ,我可以這樣做:

[root@www ~]# grep -n 'g..d' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
9:Oh! The soup taste good.
16:The world <Happy> is the same with "glad".

因為強調 g 與 d 之間一定要存在兩個字元,因此,第 13 行的 god 與第 14 行的 gd 就不會被列出來啦!再來,如果我想要列出有 oo, ooo, oooo 等等的資料, 也就是說,至少要有兩個(含) o 以上,該如何是好?是 o* 還是 oo* 還是 ooo* 呢? 雖然你可以試看看結果, 不過結果太佔版面了 @_@ ,所以,我這裡就直接說明。

因為 * 代表的是『重複 0 個或多個前面的 RE 字符』的意義, 因此,『o*』代表的是:『擁有空字元或一個 o 以上的字元』, 特別注意,因為允許空字元(就是有沒有字元都可以的意思),因此,『grep -n 'o*' regular_express.txt 』將會把所有的資料都列印出來螢幕上!

那如果是『oo*』呢?則第一個 o 肯定必須要存在,第二個 o 則是可有可無的多個 o , 所以,凡是含有 o, oo, ooo, oooo 等等,都可以被列出來~

同理,當我們需要『至少兩個 o 以上的字串』時,就需要 ooo* ,亦即是:

[root@www ~]# grep -n 'ooo*' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

這樣理解 * 的意義了嗎?好了,現在出個練習,如果我想要字串開頭與結尾都是 g,但是兩個 g 之間僅能存在至少一個 o ,亦即是 gog, goog, gooog.... 等等,那該如何?

[root@www ~]# grep -n 'goo*g' regular_express.txt
18:google is the best tools for search keyword.
19:goooooogle yes!

如此瞭解了嗎?再來一題,如果我想要找出 g 開頭與 g 結尾的字串,當中的字元可有可無,那該如何是好?是『g*g』嗎?

[root@www ~]# grep -n 'g*g' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
3:Football game is not use feet only.
9:Oh! The soup taste good.
13:Oh!  My god!
14:The gd software is a library for drafting programs.
16:The world <Happy> is the same with "glad".
17:I like dog.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

但測試的結果竟然出現這麼多行?太詭異了吧?其實一點也不詭異,因為 g*g 裡面的 g* 代表『空字元或一個以上的 g』 在加上後面的 g ,因此,整個 RE 的內容就是 g, gg, ggg, gggg , 因此,只要該行當中擁有一個以上的 g 就符合所需了!

那該如何得到我們的 g....g 的需求呢?呵呵!就利用任意一個字元『.』啊! 亦即是:『g.*g』的作法,因為 * 可以是 0 或多個重複前面的字符,而 . 是任意字元,所以: 『.* 就代表零個或多個任意字元』的意思啦!

[root@www ~]# grep -n 'g.*g' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
14:The gd software is a library for drafting programs.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

因為是代表 g 開頭與 g 結尾,中間任意字元均可接受,所以,第 1, 14, 20 行是可接受的喔! 這個 .* 的 RE 表示任意字元是很常見的,希望大家能夠理解並且熟悉! 再出一題,如果我想要找出『任意數字』的行列呢?因為僅有數字,所以就成為:

[root@www ~]# grep -n '[0-9][0-9]*' regular_express.txt
5:However, this dress is about $ 3183 dollars.
15:You are the best is mean you are the no. 1.

雖然使用 grep -n '[0-9]' regular_express.txt 也可以得到相同的結果, 但鳥哥希望大家能夠理解上面指令當中 RE 表示法的意義才好!


  • 例題五、限定連續 RE 字符範圍 {}

在上個例題當中,我們可以利用 . 與 RE 字符及 * 來設定 0 個到無限多個重複字元, 那如果我想要限制一個範圍區間內的重複字元數呢?舉例來說,我想要找出兩個到五個 o 的連續字串,該如何作?這時候就得要使用到限定範圍的字符 {} 了。 但因為 { 與 } 的符號在 shell 是有特殊意義的,因此, 我們必須要使用跳脫字符 \ 來讓他失去特殊意義才行。 至於 {} 的語法是這樣的,假設我要找到兩個 o 的字串,可以是:

[root@www ~]# grep -n 'o\{2\}' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

這樣看似乎與 ooo* 的字符沒有什麼差異啊?因為第 19 行有多個 o 依舊也出現了! 好,那麼換個搜尋的字串,假設我們要找出 g 後面接 2 到 5 個 o ,然後再接一個 g 的字串,他會是這樣:

[root@www ~]# grep -n 'go\{2,5\}g' regular_express.txt
18:google is the best tools for search keyword.

嗯!很好!第 19 行終於沒有被取用了(因為 19 行有 6 個 o 啊!)。 那麼,如果我想要的是 2 個 o 以上的 goooo....g 呢?除了可以是 gooo*g ,也可以是:

[root@www ~]# grep -n 'go\{2,\}g' regular_express.txt
18:google is the best tools for search keyword.
19:goooooogle yes!

呵呵!就可以找出來啦~


小標題的圖示基礎正規表示法字符彙整 (characters)

經過了上面的幾個簡單的範例,我們可以將基礎的正規表示法特殊字符彙整如下:

RE 字符意義與範例
^word意義:待搜尋的字串(word)在行首!
範例:搜尋行首為 # 開始的那一行,並列出行號
grep -n '^#' regular_express.txt
word$意義:待搜尋的字串(word)在行尾!
範例:將行尾為 ! 的那一行列印出來,並列出行號
grep -n '!$' regular_express.txt
.意義:代表『一定有一個任意字元』的字符!
範例:搜尋的字串可以是 (eve) (eae) (eee) (e e), 但不能僅有 (ee) !亦即 e 與 e 中間『一定』僅有一個字元,而空白字元也是字元!
grep -n 'e.e' regular_express.txt
\意義:跳脫字符,將特殊符號的特殊意義去除!
範例:搜尋含有單引號 ' 的那一行!
grep -n \' regular_express.txt
*意義:重複零個到無窮多個的前一個 RE 字符
範例:找出含有 (es) (ess) (esss) 等等的字串,注意,因為 * 可以是 0 個,所以 es 也是符合帶搜尋字串。另外,因為 * 為重複『前一個 RE 字符』的符號, 因此,在 * 之前必須要緊接著一個 RE 字符喔!例如任意字元則為 『.*』 !
grep -n 'ess*' regular_express.txt
[list]意義:字元集合的 RE 字符,裡面列出想要擷取的字元!
範例:搜尋含有 (gl) 或 (gd) 的那一行,需要特別留意的是,在 [] 當中『謹代表一個待搜尋的字元』, 例如『 a[afl]y 』代表搜尋的字串可以是 aay, afy, aly 即 [afl] 代表 a 或 f 或 l 的意思!
grep -n 'g[ld]' regular_express.txt
[n1-n2]意義:字元集合的 RE 字符,裡面列出想要擷取的字元範圍!
範例:搜尋含有任意數字的那一行!需特別留意,在字元集合 [] 中的減號 - 是有特殊意義的,他代表兩個字元之間的所有連續字元!但這個連續與否與 ASCII 編碼有關,因此,你的編碼需要設定正確(在 bash 當中,需要確定 LANG 與 LANGUAGE 的變數是否正確!) 例如所有大寫字元則為 [A-Z]
grep -n '[A-Z]' regular_express.txt
[^list]意義:字元集合的 RE 字符,裡面列出不要的字串或範圍!
範例:搜尋的字串可以是 (oog) (ood) 但不能是 (oot) ,那個 ^ 在 [] 內時,代表的意義是『反向選擇』的意思。 例如,我不要大寫字元,則為 [^A-Z]。但是,需要特別注意的是,如果以 grep -n [^A-Z] regular_express.txt 來搜尋,卻發現該檔案內的所有行都被列出,為什麼?因為這個 [^A-Z] 是『非大寫字元』的意思, 因為每一行均有非大寫字元,例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小寫字
grep -n 'oo[^t]' regular_express.txt
\{n,m\}意義:連續 n 到 m 個的『前一個 RE 字符』
意義:若為 \{n\} 則是連續 n 個的前一個 RE 字符,
意義:若是 \{n,\} 則是連續 n 個以上的前一個 RE 字符!
 範例:在 g 與 g 之間有 2 個到 3 個的 o 存在的字串,亦即 (goog)(gooog)
grep -n 'go\{2,3\}g' regular_express.txt

再次強調:『正規表示法的特殊字元』與一般在指令列輸入指令的『萬用字元』並不相同, 例如,在萬用字元當中的 * 代表的是『 0 ~ 無限多個字元』的意思,但是在正規表示法當中, * 則是『重複 0 到無窮多個的前一個 RE 字符』的意思~使用的意義並不相同,不要搞混了!

舉例來說,不支援正規表示法的 ls 這個工具中,若我們使用 『ls -l * 』 代表的是任意檔名的檔案,而 『ls -l a* 』代表的是以 a 為開頭的任何檔名的檔案, 但在正規表示法中,我們要找到含有以 a 為開頭的檔案,則必須要這樣:(需搭配支援正規表示法的工具)

ls | grep -n '^a.*'
例題:
以 ls -l 配合 grep 找出 /etc/ 底下檔案類型為連結檔屬性的檔名
答:
由於 ls -l 列出連結檔時標頭會是『 lrwxrwxrwx 』,因此使用如下的指令即可找出結果:
ls -l /etc | grep '^l'
若僅想要列出幾個檔案,再以『 |wc -l 』 來累加處理即可。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值