本文轉自chinaunix http://bbs.chinaunix.net/thread-4246512-1-1.html 作者reyleon
我們知道, 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, 所以就輸出了第一行這條記錄.
1 $ awk '/555-5553/ { print $0 }' myfile 2 Amelia 555-5553 amelia.zodiacusque@gmail.com F
二. 比較表示式做為 pattern
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" 的, 輸出這條記錄.
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"為真(不為空).
如:
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的, 或者其他亂七八糟的, 等等..:
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
四. 空 pattern
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.
如:
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了.