正則表達式就是由一系列特殊字符組成的字符串, 其中每個特殊字符都被稱為元字符, 這些元字符并不表示為它們字面上的含義, 而會被解釋為一些特定的含義. 具個例子, 比如引用符號, 可能就是表示某人的演講內容, 同上, 也可能表示為我們下面將要講到的符號的元-含義. 正則表達式其實是由普通字符和元字符共同組成的集合, 這個集合用來匹配(或指定)模式.

一個正則表達式會包含下列一項或多項:

  • 一個字符集. 這里所指的字符集只包含普通字符, 這些字符只表示它們的字面含義. 正則表達式的最簡單形式就是包含字符集, 而不包含元字符.

  • . 指定了正則表達式所要匹配的文本在文本行中所處的位置. 比如, ^, 和$就是錨.

  • 修飾符. 它們擴大或縮小(修改)了正則表達式匹配文本的范圍. 修飾符包含星號, 括號, 和反斜杠.

正則表達式最主要的目的就是用于(RE)文本搜索與字符串操作. (譯者注: 以下正則表達式也會被簡稱為RE.) RE能夠匹配單個字符或者一個字符集 -- 即, 一個字符串, 或者一個字符串的一部分.

  • 星號 -- * -- 用來匹配它前面字符的任意多次, 包括0次.

    "1133*"匹配11 + 一個或多個3 + 也允許后邊還有其他字符: 113, 1133, 111312, 等等.

  • 點 -- . -- 用于匹配任意一個字符, 除了換行符. [1]

    "13." 匹配13 + 至少一個任意字符(包括空格): 1133, 11333, 但不能匹配13 (因為缺少"."所能匹配的至少一個任意字符).

  • 脫字符號 -- ^ -- 匹配行首, 但是某些時候需要依賴上下文環境, 在RE中, 有時候也表示對一個字符集取反.

  • 美元符 -- $ -- 在RE中用來匹配行尾.

    "XXX$" 匹配行尾的XXX.

    "^$" 匹配空行.

  • 中括號 -- [...] -- 在RE中, 將匹配中括號字符集中的某一個字符.

    "[xyz]" 將會匹配字符x, y, 或z.

    "[c-n]" 匹配字符c到字符n之間的任意一個字符.

    "[B-Pk-y]" 匹配從BP, 或者從ky之間的任意一個字符.

    "[a-z0-9]" 匹配任意小寫字母或數字.

    "[^b-d]" 將會匹配范圍在bd之外的任意一個字符. 這就是使用^對字符集取反的一個實例. (就好像在某些情況下, !所表達的含義).

    將多個中括號字符集組合使用, 能夠匹配一般的單詞或數字. "[Yy][Ee][Ss]"能夠匹配yes, Yes, YES, yEs, 等等. "[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]" 可以匹配社保碼(Social Security number).

  • 反斜杠 -- \ -- 用來轉義某個特殊含義的字符, 這意味著, 這個特殊字符將會被解釋為字面含義.

    "\$"將會被解釋成字符"$", 而不是RE中匹配行尾的特殊字符. 相似的, "\\"將會被解釋為字符"\".

  • 轉義"尖括號" -- \<...\> -- 用于匹配單詞邊界.

    尖括號必須被轉義才含有特殊的含義, 否則它就表示尖括號的字面含義.

    "\<the\>" 完整匹配單詞"the", 不會匹配"them", "there", "other", 等等.

     

    bash$ cat textfile
    This is line 1, of which there is only one instance.
    This is the only instance of line 2.
    This is line 3, another line.
    This is line 4.



    bash$ grep 'the' textfile
    This is line 1, of which there is only one instance.
    This is the only instance of line 2.
    This is line 3, another line.



    bash$ grep '\<the\>' textfile
    This is the only instance of line 2.
  • 擴展的正則表達式. 添加了一些額外的匹配字符到基本集合中. 用于egrep, awk, 和Perl.

  • 問號 -- ? -- 匹配它前面的字符, 但是只能匹配1次或0次. 通常用來匹配單個字符.

  • 加號 -- + -- 匹配它前面的字符, 能夠匹配一次或多次. 與前面講的*號作用類似, 但是不能匹配0個字符的情況.

      1 # GNU版本的sed和awk能夠使用"+",
    2 # 但是它需要被轉義一下.

    4 echo a111b | sed -ne '/a1\+b/p'
    5 echo a111b | grep 'a1\+b'
    6 echo a111b | gawk '/a1+b/'
    7 # 上邊3句的作用相同.

    9 # 感謝, S.C.
  • 轉義"大括號" -- \{ \} -- 在轉義后的大括號中加上一個數字, 這個數字就是它前面的RE所能匹配的次數.

    大括號必須經過轉義, 否則, 大括號僅僅表示字面含意. 這種用法并不是基本RE集合中的一部分, 僅僅是個技巧而以.

    "[0-9]\{5\}" 精確匹配5個數字 (所匹配的字符范圍是0到9).

    Note

    使用大括號形式的RE是不能夠在"經典"(非POSIX兼容)的awk版本中正常運行的. 然而, gawk命令中有一個--re-interval選項, 使用這個選項就允許使用大括號形式的RE了(無需轉義).

     

    bash$ echo 2222 | gawk --re-interval '/2{3}/'
    2222

    Perl與某些版本的egrep不需要轉義大括號.

  • 圓括號 -- ( ) -- 括起一組正則表達式. 當你想使用expr進行子字符串提取(substring extraction)的時候, 圓括號就有用了. 如果和下面要講的"|"操作符結合使用, 也非常有用.

  • 豎線 -- | -- 就是RE中的"或"操作符, 使用它能夠匹配一組可選字符中的任意一個.

     

    bash$ egrep 're(a|e)d' misc.txt
    People who read seem to be better informed than those who do not.
    The clarinet produces sound by the vibration of its reed.

Note

與GNU工具一樣, 某些版本的sed, ed, 和ex一樣能夠支持擴展正則表達式, 上邊這部分就描述了擴展正則表達式.

  • POSIX字符類. [:class:]

    這是另外一種, 用于指定匹配字符范圍的方法.

  • [:alnum:] 匹配字母和數字. 等價于A-Za-z0-9.

  • [:alpha:] 匹配字母. 等價于A-Za-z.

  • [:blank:] 匹配一個空格或是一個制表符(tab).

  • [:cntrl:] 匹配控制字符.

  • [:digit:] 匹配(十進制)數字. 等價于0-9.

  • [:graph:] (可打印的圖形字符). 匹配ASCII碼值范圍在33 - 126之間的字符. 與下面所提到的[:print:]類似, 但是不包括空格字符(空格字符的ASCII碼是32).

  • [:lower:] 匹配小寫字母. 等價于a-z.

  • [:print:] (可打印的圖形字符). 匹配ASCII碼值范圍在32 - 126之間的字符. 與上邊的[:graph:]類似, 但是包含空格.

  • [:space:] 匹配空白字符(空格和水平制表符).

  • [:upper:] 匹配大寫字母. 等價于A-Z.

  • [:xdigit:] 匹配16進制數字. 等價于0-9A-Fa-f.

    Important

    POSIX字符類通常都要用引號或雙中括號([[ ]])引起來.

     

    bash$ grep [[:digit:]] test.file
    abc=723

    如果在一個受限的范圍內, 這些字符類甚至可以用在通配(globbing)中.

     

    bash$ ls -l ?[[:digit:]][[:digit:]]?
    -rw-rw-r-- 1 bozo bozo 0 Aug 21 14:47 a33b

    如果想了解POSIX字符類在腳本中的使用情況, 請參考例子 12-18例子 12-19.

Sed, awk, 和Perl在腳本中一般都被用作過濾器, 這些過濾器將會以RE為參數, 對文件或者I/O流進行"過濾"或轉換. 請參考例子 A-12例子 A-17, 來詳細了解這種用法.

對于RE這個復雜的主題, 標準的參考材料是Friedl的Mastering Regular Expressions. 由Dougherty和Robbins所編寫的Sed & Awk這本書, 也對RE進行了清晰的論述. 如果想獲得這些書的更多信息, 請察看參考文獻.

注意事項

[1]

因為sed, awk, 和grep通常用于處理單行, 但是不能匹配一個換行符. 如果你想處理多行輸入的話, 那么你可以使用"點"來匹配換行符.

  1 #!/bin/bash

3 sed -e 'N;s/.*/[&]/' << EOF # Here Document
4 line1
5 line2
6 EOF
7 # 輸出:
8 # [line1
9 # line2]
10 
11 
12 
13 echo
14 
15 awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' << EOF
16 line 1
17 line 2
18 EOF
19 # 輸出:
20 # line
21 # 1
22 
23 
24 # 感謝, S.C.
25
26 exit 0