阿旺的 Linux 開竅手冊







基礎篇
進階篇
補腦篇
版權所有,引用請註明出處

 進階篇

Advanced Chapter 2 : 正規表示法/過濾程式

2.0 正規表示法簡介
2.1 基礎正規表示法(RE/BRE)
        Bracket Expressions(POSIX 中括號表示法)
            POSIX Character(POSIX 字集)
        .:匹配任何單一字元
        *:匹配前字元從零到無限重複
        ^:匹配起始位置的字串
        $:匹配結束位置的字串
        &:記憶匹配到的字串
        {a,b}:匹配限定重複前字元
        ( ):集合匹配前字串
        < >:匹配單字
        ( )\1:向後參考記憶匹配
        |:或匹配
2.2 延伸正規表示法 (ERE)
        |:或匹配
        +:匹配前面一個到無限重複字元
        ?:匹配前面零到一個重複字元
2.3 過濾器簡介
        grep 檔案中尋找字串
           egrep
           frgep
        cut 擷取欄位
        col 過濾控制字元
        tr 字元轉換
        sort 排序
        uniq 刪除相鄰重複的行





















正規表示法/過濾程式

2.0 正規表示法簡介
〝正規表示法〞(Regular Expression 縮寫為 RE 或 regex 或 regexp)或叫〝正則表達式〞,其作用為:「匹配符合某一規則的字串或字元(字符)」。

例如公司許多的產品目錄,顏色的標示有時用〝color〞有時用〝colour〞,如某天我要搜尋關鍵字〝color〞或〝colour〞如用正規表示法我只要用〝colou*r〞就可找到〝color〞或〝colour〞這兩種拼法,也時常用正規表示法〝\<[^aeiouyAEIOUY]*\>〞來找出無母音的單字來初步檢查看有無打字錯誤,只要花少許時間學習,就能擁有〝正規表示法〞的〝法眼〞很方便和實用。

正規表示法或延伸正規表示法所書寫的匹配敘述叫〝樣板〞(pattern),如上例的〝\<[^aeiouyAEIOUY]*\>〞或〝colou*r〞。

上例只是正規表示法的牛刀小試,正規表示法原本只流行在 UNIX 的一些工具程式如 grep, sed 等,因太強大和好用,故逐漸擴展到其他地方。甚至連一向不屑 Unix/Linux 的微軟在其 Wold/Excel 中也對正規表示法提供了相當程度的支援,故學會了可應用在許多的地方,很值得一學。

<下圖為 MS Word 用正規表示法尋找單字〝The〞或〝the〞>


正規表示法很多人會和萬用字元搞混在一起而分不清,不過這也難怪,因正規表示法和萬用字元所用的符號部分重疊,但所代表的意義卻不一定一樣。更讓人搞混的為 UNIX 自從 1975 年發表了 UNXI V6,其中新增了〝globbing patterns〞(又叫〝glob〞)[註 2.0])擴充了萬用字元語法,從此萬用字元也有 Bracket Expressions 的功能和正規表示法的語法有部分重疊(雖然結果不一定相同)。

正規表示法可想像為萬用字元的加強版,可更細膩和彈性來匹配某一規則的字串。但正規表示法也有明顯不足的地方;例如正規表示法的語法對地球人來說就像火星文不易閱讀。且正規表示法也有許多的〝方言〞,例如文字編輯器 vim 和另一齊名的工具 emacs 或和指令 grep 其正規表示的語法可能不完全相容。另外並非所有的指令或工具都有支援正規表示法。

為了達到最大的相容性,各工具如有支援正規表示法多會〝盡量〞符合〝POSIX〞標準[註 2.0A],但部分工具也多少加些標準外的〝方言〞,雖有其便利性,但也犧牲了流通性和標準,故 POSIX 以外的〝方言〞不在此介紹。

解釋正規表示法之前先舉個例子來說明萬用字元的最大缺點,如下例目的為用萬用字元列出〝/etc〞目錄內第一個字元為大寫的檔案或目錄:

例:

$ cd /etc
$ LANG=POSIX ←設定語系為〝POSIX〞(同等〝LANG=C〞或〝LANG=〞為清除所有設定的語系)
$ ls -d [A-Z]* | head -n 5 ←用萬用字元列出前 5 個第一個字元為大寫的檔案或目錄
ConsoleKit 
DIR_COLORS
Muttrc
DIR_COLORS.xterm 
Muttrc.local  
$ LANG=en_US.UTF-8 ←設定語系為〝en_US.UTF-8〞
$ ls -d [A-Z]* | head -n 5 ←同一動作再作一次
bashrc ←輸出不一樣了?
blkid
bluetooth
bonobo-activation
capi.conf

以上的實驗說明了萬用字元的最大缺點之一即同一指令在不同的機器或環境輸出會不一樣(不同的語系設定可能會影響萬用字元的排序)。這也是基礎篇中選擇安裝的語系為了後續的範例有一致的輸出而建議語言的選項為〝English〞(語系為〝en_US.UTF-8〞)的原因[註 2.0B]。

如果同一功能用 ls 配合有支援正規表示法的 grep 重寫就會有一致的輸出結果,不再有萬用字元因不同環境而影響輸出。

例:
$ cd /etc
$ LANG=POSIX
$ ls -d * | grep '[A-Z].*' | head -n 5 ←用 ls 配合 grep 列出前 5 個第一個字元為大寫的檔案或目錄
ConsoleKit 
DIR_COLORS
DIR_COLORS.xterm
Muttrc
Muttrc.local  
$ LANG=en_US.UTF-8 ←設定語系為〝en_US.UTF-8〞
$ ls -d * | grep '[A-Z].*' | head -n 5 ←再測試看結果
ConsoleKit ←結果一致了
DIR_COLORS
DIR_COLORS.xterm
Muttrc
Muttrc.local

正規表示法本身並不難,但要正確的匹配是需要經驗和多練習, 正規表示法可分 基礎正規表示法(RE) / 延伸正規表示法(ERE),但不同的工具軟體支援的程度不一,如下為 Unix/Linux 常用的工具對正規表示法所支援的程度。

Utility 基礎正規表示法 延伸正規表示法
shell    
vi  
locate  
find
grep
sed
awk


^ back on top ^



2.1 基礎正規表示法(RE/BRE)

基礎正規表示法(Basic Regular Expressions)常簡寫為 regex、RE、BRE 或叫〝posix-basic〞。基礎正規表示法為正規表示法中最基本的用法,一般如沒特別說明,正規表示法即指基礎正規表示法;用如 man 查某指令的用法有出現支援〝regexp〞或〝regex〞或〝posix-basic〞就表示有支持基礎正規表示法。

基礎正規表示法對括號中的〝{ }〞, 〝( )〞,〝< >〞和〝|〞視為保留的表示符號(meta-character)有其意義,故要加上跳脫字元,這是和延伸正規表示法(ERE)最明顯的區別。

由於 vi(vim) 編輯器本身就對正規表示法有良好的支援,且如有匹配的字串會反白顯示(請在 vi 的環境設定中設〝:set hlsearch〞使之反白顯示符合匹配的文字),很適合用來練習正規表示法,故以下範例都用 vi 一般模式的搜尋來實驗。

請用 vi 輸入如下網路隨機找到的英文繞口令,並存檔為〝re.txt〞,因在介紹 延伸正規表示法grepsed 時可能會再用到(如懶的輸入就用複製-貼上)

(vi 編輯)
busy buzzing bumblebees buzzing busying
6 silly sisters selling shining shoes
The driver was drunk and drove the doctor's car into deep ditch.
can you can a can as a canner can can a can

google Goggles Solves SUDOKU Puzzles.
How much oil boil can a gum boil boil if a gum boil can boil oil?
Where's the peck of pickled peppers Peter Piper picked?
55 Flags freely flutter from the floating frigate


2.2 延伸正規表示法(ERE)

但為什麼要有〝延伸正規表示法〞呢?阿旺我個人認為(個人認為不一定對,有空我再考證一下)因基礎正規表示法在定義的時候漏掉了或匹配的〝|〞。

為什要為了一個或匹配符號的〝|〞而定義延伸正規表示法?符號〝|〞這麼重要嗎?是的!!舉簡單的例子,假設我不用〝|〞,但我要匹配單字〝as〞或〝if〞我可能可寫成〝[ai][sf]〞但此時你要保佑不要匹配到單字〝is〞。

但隨便增加或匹配符號的〝|〞到基礎正規表示法會有相容問題,如以前寫的 pattern 只是要匹配字元〝|〞但並不是要進行或匹配運算。 故解決方法為原基礎正規表示法要用或匹配要加跳脫字元寫成〝\|〞 另新增另一表示法叫〝延伸正規表示法〞則直接用〝|〞表示或匹配也順便修改了些東東。

延伸正規表示法(Extended Regular Expression)或叫〝posix-Extended〞常簡寫為 ERE,和基礎正規表示法不同的地方如下。

所以延伸正規表示法也沒什特別不是嗎?一般來說指令如有支援延伸正規表示法,且要指定用延伸正規表示法來匹配時其選項為〝-E〞,例如 grep -E 。而 grep 也是支援延伸正規表示法的典行指令。

延伸正規表示法新增的項目如下:


^ back on top ^




2.3 過濾器簡介
Unix/Linux 有一群很特別的工具軟體叫〝過濾器〞(filter),過濾器有些是不能由鍵盤直接輸入資料或單獨的使用,而是要經管線重定向來操作,過濾器基本以〝行〞(line)為單位來過濾文字、搜尋、修改、取代、插入、刪除或統計等來處理資料。

過濾器的操作基本上是輸出到 stdout 也就是螢幕,如要存檔要再重定向到檔案如 cat fileA | tr -s '\n' > fileB

過濾器工具軟體常用的有 grepcutcoltruniqsortsedawk 等,其中 sedawk 有自己專屬的腳本語言另成一格且相對複雜,故在 sed 和 awk 章節獨立說明。


^ back on top ^











www.reliablecounter.com
digital mastering

[註2.0]〝globbing patterns〞(又叫〝glob〞)中文好像有人叫〝通配〞,目的為類似萬用字元來匹配字串,用因年代久遠,連〝glob〞這一辭如何而來的都已不可考。

[註2.0A]〝POSIX〞為〝Portable Operating System Interface〞(可移植作業系統介面),因 UNIX (包括 Linux)因後續的徒子徒孫版本眾多,為了要求不同版本也有一致的操作和輸出,IEEE (電機電子工程師學會)制定了 POSIX 標準供大家參考。

[註2.0B]可輸入 locale -a 來查詢有那些可用的語系可用(參考http://blog.csdn.net/ktyl2000/article/details/4156769)。