(轉)關於 awk 的 pattern(模式)

本文轉自chinaunix http://bbs.chinaunix.net/thread-4246512-1-1.html   做者reyleonhtml

咱們知道, awk程序由一系列 pattern 以及與之對應的 action 組成的 rule 組成,rule之間用";"分號隔開, 一條輸入記錄與 pattern 匹配則執行與之關聯的action, 以下所示:

awk ' 
        pattern { action };
        pattern { action };
        .....
'

但是, 不少人並不清楚什麼東西能夠作爲 pattern下面就來聊聊這些個事兒. 如下文本作爲測試文本:正則表達式

 1 $ cat myfile
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R

 

首先, 要記住, 凡是被 {} 包裹的, 就是 action, 或者說, action 必然被 {} 包裹着
凡是沒有被{}包裹的, 就是pattern, 或者說pattern不能被{}包裹着. 

一. 正則表達式作爲 pattern

最多見的, 就是一個正則表達式作爲一個 pattern了, 如:

測試

1 awk '/555-5553/ { print $0 }' myfile

/555-5553/ 就是一個正則表達式, 若是輸入記錄匹配555-5553, 就輸出這條記錄, 這裏只有第一行匹配 555-5553, 因此就輸出了第一行這條記錄.ui

1 $ awk '/555-5553/ { print $0 }' myfile
2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F

二. 比較表達式作爲 patternspa

1 $ awk '$NF == "A" { print $0 }' myfile
2 Anthony    555-3412  anthony.asserturo@hotmail.com    A
3 Becky      555-7685  becky.algebrarum@gmail.com       A
4 Bill       555-1675  bill.drowning@hotmail.com        A
5 Martin     555-6480  martin.codicibus@hotmail.com     A

最後一個字段爲 "A" 的, 輸出這條記錄..net

1 $ awk '$NF != "A" { print $0 }' myfile
2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
3 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
4 Camilla    555-2912  camilla.infusarum@skynet.be      R
5 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
6 Julie      555-6699  julie.perscrutabor@skeeve.com    F
7 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R

最後一個字段不爲 "A" 的, 輸出這條記錄.

三. 常量表達式作爲 pattern

這種pattern通常是最不易被新手理解的, 事實上, 既然是 pattern 匹配, 結果就只有兩種狀況, 要麼匹配(即爲真),就執行後面的 action, 要麼不匹配(即爲假), 就不會執行後面的action.
因此, awk 的規則基本上也就是:

awk ' 真 { 執行代碼 }; 假 { 不執行代碼 }' 

也理解爲:

awk ' 條件 { 動做 } 條件 { 動做 } ' 

什麼東西能夠作爲一個常量? 一個數字, 或者一個字符串, 均可以作爲一個常量 pattern. 那這裏就有一個龜腚了:

凡是非0的數字, 就表示pattern匹配成功, 也就是pattern爲真. 不然表示匹配失敗, 爲假.
凡是非空的字符串, 就表示pattern匹配成功, 也就是pattern爲真. 不然表示匹配失敗, 爲假. 

注意: 字符串是由引號引發來的! 好比數字 0 與 字符串 "0" 不是同樣的. 數字0爲假, 字符串"0"爲真(不爲空).

如:unix

 1 $ awk '1 { print $0 }' myfile
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R
 1 $ awk '2 { print $0 }' myfile
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R
1 $ awk '0 { print $0 }' myfile
2 // 數字 0 作爲 pattern, 0爲假, pattern 匹配失敗, 因此不執行 print $0, 沒有打印.

 

 1 $ awk ' "0" { print $0 }' myfile
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R
13 // 字符串 "0" 作爲 pattern, 爲真, pattern 匹配成功, 因此執行 print $0, 打印.

還有一些, 多是寫錯的賦值語句作爲了pattern的, 或者其餘亂七八糟的, 等等..:code

1 $ awk 'a=0'  myfile // 數字0. 假, 沒輸出.

 

 1 $ awk 'a=1'  myfile // 1 爲真. 
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R
 1 $ awk 'x-1'  myfile // x 爲未定義的變量, 作數學運算, 結果爲 -1 , 因 -1 也是非0的數字常量, pattern 匹配成功, 爲真, print $0.
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R

 

1 1 $ awk 'xxoo'  myfile //xxoo爲變量, 未賦值, 爲假
 1 $ awk '"xxoo"'  myfile // 字符串, 真.
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R

四. 空 patternhtm

 1 $ awk '{print $0}' myfile
 2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
 3 Anthony    555-3412  anthony.asserturo@hotmail.com    A
 4 Becky      555-7685  becky.algebrarum@gmail.com       A
 5 Bill       555-1675  bill.drowning@hotmail.com        A
 6 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
 7 Camilla    555-2912  camilla.infusarum@skynet.be      R
 8 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
 9 Julie      555-6699  julie.perscrutabor@skeeve.com    F
10 Martin     555-6480  martin.codicibus@hotmail.com     A
11 Samuel     555-3430  samuel.lanceolis@shu.edu         A
12 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R

// 這裏沒有 pattern, 空的, empty pattern, 那麼就表示匹配輸入記錄永遠成功, 也就是說永遠爲真, 這是龜腚. action永遠都會執行.

咱們知道, awk 的rule 就是由一系列 pattern 和 action 構成, 這裏所謂的空 pattern, 也能夠說是省略了 pattern, 那麼 action 可不能夠省略呢?
事實上, action也是能夠省略的, 但若是省略了的話,它就會有一個默認的action行爲, 即 { print $0 } !
不少人新手常常搞不懂一下的代碼:

awk '{a=1}1' myfile

常常會碰到有人問, 這個代碼後面的1是幹嗎的? 其實, 咱們拆分下 awk 的 rule 就明白了.
awk '{a=1}1' 這個語句包含了兩條規則:

awk '
        [空pattern] {a=1}    #第一條規則
        1 [{省略的action}]   #第二條規則
'


第一條rule: {a=1} , 這條規則這裏有一個{}大括號包裹着, 表示這是一個 action, 可是省略了pattern, 即空pattern, 
上面說了, 空pattern是永遠匹配爲真的, 
因此{a=1}這個action會針對每條輸入記錄對執行,只是咱們看不到它的具體表現而已.

第二條rule: 1, 這條規則僅僅只有一個1字, 沒有被{}大括號包裹着, 
因此這個1是一個pattern, 省略了{action}, 而這個數字 1 , 實際上就是一個常量表達式pattern, 因它爲非0的數字,因此pattern匹配成功,爲真,就執行action,
由於這裏省略了{action},就觸發默認的行爲,而默認的action行爲是print $0,即打印這條記錄.

再如: awk '1;1' ,省略了兩個action, 因此這條實際上就是兩個 {print $0}{print $0}.

因此, 凡是action只是要輸出這條記錄的, 統統均可以省略這個 action.

如:blog

1 $ awk '/Amelia/ || /Martin/'  myfile
2 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
3 Martin     555-6480  martin.codicibus@hotmail.com     A
4 $ awk '$NF ~ /F/'  myfile
5 Amelia     555-5553  amelia.zodiacusque@gmail.com     F
6 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
7 Julie      555-6699  julie.perscrutabor@skeeve.com    F
8 $ awk 'NR==5'  myfile
9 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R

五. 特殊的 pattern: BEGIN, END ..

在 awk 中, 確定會常常看到 BEGIN, END 這兩個玩意兒. 如 awk 'BEGIN { ... } END { ... } '

實際上, BEGIN 和 END 只是兩個特殊的 pattern . 相似的還有 BEGINFILE,  ENDFILE. 

BEGIN 在讀入文件以前匹配成功, 即爲在讀入文件以前這條 rule 就已經執行了.
END 在處理完文件以後才匹配陳宮, 即在處理完文件以後纔會執行這條 rule.

1 $ awk 'BEGIN { n=5 } NR==n { print $0 } END { print $0 }' myfile
2 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
3 Jean-Paul  555-2127  jeanpaul.campanorum@nyu.edu      R

分析下這條 awk 語句:
首先, 它包含三條規則
1. BEGIN { n=5 }  ,BEGIN 爲 特殊pattern, {n=5} 爲 action
2. NR==n { print $0 }, NR==n 是一個比較表達式pattern, { print $0 } 爲action.
3. END { print $0 }, END 也是一個特殊的pattern.

BEGIN 模式通常讀入文件以前經常使用的是作一些相關的定義操做, 這裏設定變量n=5. 
而後awk開始處理記錄, 當 NR==n 時, 即處理到咱們定義的那條記錄時(第5條記錄時), 執行 print $0, 輸出這條記錄.
最後是END模式, awk處理完文件裏, END模式匹配成功,執行print $0, 即輸出最後一條記錄.
因此, 結果是輸出第5條記錄和最後一條記錄.


六. 模式範圍: begpat, endpat

這個模式範圍, 是由兩個 pattern 組成, 每一個 pattern能夠是任意的非特殊類型(非BEGIN/END模式類型)的pattern類型(能夠是正則,比較,常量等pattern).
這個模式範圍匹配的規則有點兒特殊, 這裏以一個"開閘放水"的例子作爲一個類比.
1. 首先以第一個pattern匹配輸入記錄, 若是第一個pattern匹配成功,就"打開放水的開關開始放水",[開關的狀態: 開], 即會當即執行後面的action.此時無論第二個pattern是否匹配.
2. 接着再匹配第二pattern, 若是第二pattern匹配失敗,開關的狀態不變,即仍是會執行action.
3. 接着繼續以第二個pattern匹配下一條輸入記錄,直到第二個pattern匹配成功. 就"關閉放水的開關中止放水",[開關的狀態: 關], 模式範圍匹配結束.
4. 以1,2,3步驟進入下一輪模式範圍匹配

如:

1 $ awk 'NR==4, /555-3430/ { print $0}' myfile
2 Bill       555-1675  bill.drowning@hotmail.com        A
3 Broderick  555-0542  broderick.aliquotiens@yahoo.com  R
4 Camilla    555-2912  camilla.infusarum@skynet.be      R
5 Fabius     555-1234  fabius.undevicesimus@ucb.edu     F
6 Julie      555-6699  julie.perscrutabor@skeeve.com    F
7 Martin     555-6480  martin.codicibus@hotmail.com     A
8 Samuel     555-3430  samuel.lanceolis@shu.edu         A

先執行 NR==4 這個 pattern 匹配, 當第四條記錄匹配成功時, 放水開關打開, 開始放水了, 即開始執行action , 執行 print $0 , 輸出第四條記錄.接着使用 /555-3430/ 當前記錄, 不成功.第5條記錄繼續執行 action.繼續以第二個pattern匹配這條記錄..不成功..,開關是開的第6條記錄繼續執行 action.繼續以第二個pattern匹配這條記錄..不成功..,開關是開的.....直到匹配 /555-3430/, 第二個pattern匹配成功. 開關關閉. 模式範圍匹配結束..開始下一輪模式範圍匹配..以上就是各類 pattern 的簡要解說了.. 至於 action, 也沒啥可說的, action通常作具體的事情.那些個流程控制語句 if/for/while 等通常都屬於action了, 不能作爲 pattern了.

相關文章
相關標籤/搜索