AWK 介紹

AWK 介紹
如果要格式化報文或從一個大的文本文件中抽取數據包,那麼a w k可以完成這些任務。它
在文本瀏覽和數據的熟練使用上性能優異。
整體來說, a w k是所有s h e l l過濾工具中最難掌握的,不知道爲什麼,也許是其複雜的語法
或含義不明確的錯誤提示信息。在學習a w k語言過程中,就會慢慢掌握諸如Bailing out 和
a w k : c m d . L i n e :等錯誤信息。可以說a w k是一種自解釋的編程語言,之所以要在s h e l l中使用a w k
是因爲a w k本身是學習的好例子,但結合a w k與其他工具諸如g r e p和s e d,將會使s h e l l編程更加
容易。
本章沒有講述a w k的全部特性,也不涉及a w k的深層次編程,(這些可以在專門講述a w k的
書籍中找到)。本章僅注重於講述使用a w k執行行操作及怎樣從文本文件和字符串中抽取信息。
本章內容有:
• 抽取域。
• 匹配正則表達式。
• 比較域。
• 向a w k傳遞參數。
• 基本的a w k行操作和腳本。
本書幾乎所有包含a w k命令的腳本都結合了s e d和g r e p,以從文本文件和字符串中抽取信
息。爲獲得所需信息,文本必須格式化,意即用域分隔符劃分抽取域,分隔符可能是任意字
符,在以後講述a w k時再詳細討論。
a w k以發展這種語言的人A h o . We n i n b e rg e r和K e r n i g h a m命名。還有n a w k和g a w k,它們擴
展了文本特性,但本章不予討論。
a w k語言的最基本功能是在文件或字符串中基於指定規則瀏覽和抽取信息。a w k抽取信息
後,才能進行其他文本操作。完整的a w k腳本通常用來格式化文本文件中的信息。
9.1 調用awk
有三種方式調用a w k,第一種是命令行方式,如:
這裏,c o m m a n d s是真正的a w k命令。本章將經常使用這種方法。
上面例子中, [ - F域分隔符]是可選的,因爲a w k使用空格作爲缺省的域分隔符,因此如果
要瀏覽域間有空格的文本,不必指定這個選項,但如果要瀏覽諸如p a s s w d文件,此文件各域
以冒號作爲分隔符,則必須指明- F選項,如:
第二種方法是將所有a w k命令插入一個文件,並使a w k程序可執行,然後用a w k命令解釋
器作爲腳本的首行,以便通過鍵入腳本名稱來調用它。
第三種方式是將所有的a w k命令插入一個單獨文件,然後調用:
- f選項指明在文件a w k _ s c r i p t _ f i l e中的a w k腳本, i n p u t _ f i l e ( s )是使用a w k進行瀏覽的文件
名。
9.2 awk腳本
在命令中調用a w k時,a w k腳本由各種操作和模式組成。
如果設置了- F選項,則a w k每次讀一條記錄或一行,並使用指定的分隔符分隔指定域,但
如果未設置- F選項,a w k假定空格爲域分隔符,並保持這個設置直到發現一新行。當新行出現
時,a w k命令獲悉已讀完整條記錄,然後在下一個記錄啓動讀命令,這個讀進程將持續到文件
尾或文件不再存在。
參照表9 - 1,a w k每次在文件中讀一行,找到域分隔符(這裏是符號#),設置其爲域n,直
至一新行(這裏是缺省記錄分隔符),然後,劃分這一行作爲一條記錄,接着a w k再次啓動下
一行讀進程。
表9-1 awk讀文件記錄的方式
域1 分隔符域2 分隔符域3 分隔符域4及換行
P. B u n n y (記錄1 ) # 0 2 / 9 9 # 4 8 # Yellow /n
J . Tr o l l (記錄2 ) # 0 7 / 9 9 # 4 8 4 2 # Brown-3 /n
9.2.1 模式和動作
任何a w k語句都由模式和動作組成。在一個a w k腳本中可能有許多語句。模式部分決定動
作語句何時觸發及觸發事件。處理即對數據進行的操作。如果省略模式部分,動作將時刻保
持執行狀態。
模式可以是任何條件語句或複合語句或正則表達式。模式包括兩個特殊字段B E G I N和
E N D。使用B E G I N語句設置計數和打印頭。B E G I N語句使用在任何文本瀏覽動作之前,之後
文本瀏覽動作依據輸入文件開始執行。E N D語句用來在a w k完成文本瀏覽動作後打印輸出文
本總數和結尾狀態標誌。如果不特別指明模式, a w k總是匹配或打印行數。
實際動作在大括號{ }內指明。動作大多數用來打印,但是還有些更長的代碼諸如i f和循環
(l o o p i n g)語句及循環退出結構。如果不指明採取動作, a w k將打印出所有瀏覽出來的記錄。
下面將深入講解這些模式和動作。
9.2.2 域和記錄
a w k執行時,其瀏覽域標記爲$ 1,$ 2 . . . $ n。這種方法稱爲域標識。使用這些域標識將更容
易對域進行進一步處理。
使用$ 1 , $ 3表示參照第1和第3域,注意這裏用逗號做域分隔。如果希望打印一個有5個域
的記錄的所有域,不必指明$ 1 , $ 2 , $ 3 , $ 4 , $ 5,可使用$ 0,意即所有域。Aw k瀏覽時,到達一新
行,即假定到達包含域的記錄末尾,然後執行新記錄下一行的讀動作,並重新設置域分隔。
注意執行時不要混淆符號$和s h e l l提示符$,它們是不同的。
爲打印一個域或所有域,使用p r i n t命令。這是一個a w k動作(動作語法用圓括號括起來)。
第9章AWK 介紹67
下載
1. 抽取域
真正執行前看幾個例子,現有一文本文件g r a d e . t x t,記錄了一個稱爲柔道數據庫的行信
息。
此文本文件有7個域,即(1)名字、(2)升段日期、(3)學生序號、(4)腰帶級別、(5)
年齡、(6)目前比賽積分、(7)比賽最高分。
因爲域間使用空格作爲域分隔符,故不必用- F選項劃分域,現瀏覽文件並導出一些數據。
在例子中爲了利於顯示,將空格加寬使各域看得更清晰。
2. 保存a w k輸出
有兩種方式保存s h e l l提示符下a w k腳本的輸出。最簡單的方式是使用輸出重定向符號>文
件名,下面的例子重定向輸出到文件w o w。
使用這種方法要注意,顯示屏上不會顯示輸出結果。因爲它直接輸出到文件。只有在保
證輸出結果正確時纔會使用這種方法。它也會重寫硬盤上同名數據。
第二種方法是使用t e e命令,在輸出到文件的同時輸出到屏幕。在測試輸出結果正確與否
時多使用這種方法。例如輸出重定向到文件d e l e t e _ m e _ a n d _ d i e,同時輸出到屏幕。使用這種
方法,在a w k命令結尾寫入| tee delete_me_and_die。
3. 使用標準輸入
在深入講解這一章之前,先對a w k腳本的輸入方法簡要介紹一下。實際上任何腳本都是從
標準輸入中接受輸入的。爲運行本章腳本,使用a w k腳本輸入文件格式,例如:
也可替代使用下述格式:
使用重定向方法:
或管道方法:
4. 打印所有記錄
a w k讀每一條記錄。因爲沒有模式部分,只有動作部分{print $0}(打印所有記錄),這個動
作必須用花括號括起來。上述命令打印整個文件。
68 第二部分文本過濾
下載
5. 打印單獨記錄
假定只打印學生名字和腰帶級別,通過查看域所在列,可知爲f i e l d - 1和f i e l d - 4,因此可以
使用$ 1和$ 4,但不要忘了加逗號以分隔域。
6. 打印報告頭
上述命令輸出在名字和腰帶級別之間用一些空格使之更容易劃分,也可以在域間使用t a b
鍵加以劃分。爲加入t a b鍵,使用t a b鍵速記引用符/ t,後面將對速記引用加以詳細討論。也可
以爲輸出文本加入信息頭。本例中加入n a m e和b e l t及下劃線。下劃線使用/ n,強迫啓動新行,
並在/ n下一行啓動打印文本操作。打印信息頭放置在B E G I N模式部分,因爲打印信息頭被界
定爲一個動作,必須用大括號括起來。在a w k查看第一條記錄前,信息頭被打印。
7. 打印信息尾
如果在末行加入end of report信息,可使用E N D語句。E N D語句在所有文本處理動作執行
完之後才被執行。E N D語句在腳本中的位置放置在主要動作之後。下面簡單打印頭信息並告
之查詢動作完成。
8. awk錯誤信息提示
幾乎可以肯定,在使用a w k時,將會在命令中碰到一些錯誤。a w k將試圖打印錯誤行,但
由於大部分命令都只在一行,因此幫助不大。
系統給出的顯示錯誤信息提示可讀性不好。使用上述例子,如果丟了一個雙引號, a w k將
返回:
第9章AWK 介紹69
下載
當第一次使用a w k時,可能被錯誤信息攪得不知所措,但通過長時間和不斷的學習,可總
結出以下規則。在碰到a w k錯誤時,可相應查找:
• 確保整個a w k命令用單引號括起來。
• 確保命令內所有引號成對出現。
• 確保用花括號括起動作語句,用圓括號括起條件語句。
• 可能忘記使用花括號,也許你認爲沒有必要,但a w k不這樣認爲,將按之解釋語法。
如果查詢文件不存在,將得到下述錯誤信息:
9. awk 鍵盤輸入
如果在命令行並沒有輸入文件g r a d e . t x t,將會怎樣?
B E G I N部分打印了文件頭,但a w k最終停止操作並等待,並沒有返回s h e l l提示符。這是因
爲a w k期望獲得鍵盤輸入。因爲沒有給出輸入文件, a w k假定下面將會給出。如果願意,順序
輸入相關文本,並在輸入完成後敲<Ct r l - D >鍵。如果敲入了正確的域分隔符, a w k會像第一個
例子一樣正常處理文本。這種處理並不常用,因爲它大多應用於大量的打印稿。
9.2.3 awk中正則表達式及其操作
在g r e p一章中,有許多例子用到正則表達式,這裏將不使用同樣的例子,但可以使用條
件操作講述a w k中正則表達式的用法。
這裏正則表達式用斜線括起來。例如,在文本文件中查詢字符串G r e e n,使用/ G r e e n /可以
查出單詞G r e e n的出現情況。
9.2.4 元字符
這裏是a w k中正則表達式匹配操作中經常用到的字符,詳細情況請參閱本書第7章正則表
達式概述。
/ ^ $ . [] | () * + ?
這裏有兩個字符第7章沒有講到,因爲它們只適用於a w k而不適用於g r e p或s e d。它們是:
+ 使用+匹配一個或多個字符。
? 匹配模式出現頻率。例如使用/X Y?Z/匹配X Y Z或Y Z。
9.2.5 條件操作符
表9 - 2給出a w k條件操作符,後面將給出其用法。
70 第二部分文本過濾
下載
表9-2 awk條件操作符
操作符描述操作符描述
< 小於> = 大於等於
< = 小於等於~ 匹配正則表達式
= = 等於!~ 不匹配正則表達式
!= 不等於
1. 匹配
爲使一域號匹配正則表達式,使用符號‘~’後緊跟正則表達式,也可以用i f語句。a w k
中i f後面的條件用()括起來。
觀察文件g r a d e . t x t,如果只要打印b r o w n腰帶級別可知其所在域爲f i e l d - 4,這樣可以寫出
表達式{if($4~/brown/) print }意即如果f i e l d - 4包含b r o w n,打印它。如果條件滿足,則打印匹
配記錄行。可以編寫下面腳本,因爲這是一個動作,必須用花括號{ }括起來。
匹配記錄找到時,如果不特別聲明, a w k缺省打印整條記錄。使用i f語句開始有點難,但
不要着急,因爲有許多方法可以跳過它,並仍保持同樣結果。下面例子意即如果記錄包含模
式b r o w n,就打印它:
2. 精確匹配
假定要使字符串精確匹配,比如說查看學生序號4 8,文件中有許多學生序號包含4 8,如
果在f i e l d - 3中查詢序號4 8,a w k將返回所有序號帶4 8的記錄:
爲精確匹配4 8,使用等號= =,並用單引號括起條件。例如$ 3 = =“4 8”,這樣確保只有4 8
序號得以匹配,其餘則不行。
3. 不匹配
有時要瀏覽信息並抽取不匹配操作的記錄,與~相反的符號是!~,意即不匹配。像原來使
用查詢b r o w n腰帶級別的匹配操作一樣,現在看看不匹配情況。表達式$0 !~/brown/,意即查
詢不包含模式b r o w n腰帶級別的記錄並打印它。
注意,缺省情況下, a w k將打印所有匹配記錄,因此這裏不必加入動作部分。
第9章AWK 介紹71
下載
可以只對f i e l d - 4進行不匹配操作,方法如下:
如果只使用命令awk$4 !="brown"{print $0} grade.txt,將返回錯誤結果,因爲用引號括起
了b r o w n,將只匹配‘b r o w n而不匹配b r o w n - 2和b r o w n - 3,當然,如果想要查詢非b r o w n - 2的腰
帶級別,可做如下操作:
4. 小於
看看哪些學生可以獲得升段機會。測試這一點即判斷目前級別分f i e l d - 6是否小於最高分
f i e l d - 7,在輸出結果中,加入這一改動很容易。
5. 小於等於
對比小於,小於等於只在操作符上做些小改動,滿足此條件的記錄也包括上面例子中的
輸出情況。
6. 大於
大於符號大家都熟知,請看例子:
希望讀者已經掌握了操作符的基本用法。
7. 設置大小寫
爲查詢大小寫信息,可使用[ ]符號。在測試正則表達式時提到可匹配[ ]內任意字符或單詞,
因此若查詢文件中級別爲g r e e n的所有記錄,不論其大小寫,表達式應爲‘ / [ G g ] r e e n /:’
8. 任意字符
抽取名字,其記錄第一域的第四個字符是a,使用句點.。表達式/ ^ . . . a /意爲行首前三個字
符任意,第四個是a,尖角符號代表行首。
9. 或關係匹配
爲抽取級別爲y e l l o w或b r o w n的記錄,使用豎線符|。意爲匹配| 兩邊模式之一。注意,使
用豎線符時,語句必須用圓括號括起來。
72 第二部分文本過濾
下載
上面例子輸出所有級別爲Ye l l o w或B r o w n的記錄。
使用這種方法在查詢級別爲G r e e n或g r e e n時,可以得到與使用[ ]表達式相同的結果。
10. 行首
不必總是使用域號。如果查詢文本文件行首包含4 8的代碼,可簡單使用下面^符號:
這裏講述了在a w k中怎樣使用第7章中涉及的表達式。像第7章的開頭提到的,所有表達式
(除字符重複出現外)在a w k中都是合法的。
複合模式或複合操作符用於形成複雜的邏輯操作,複雜程度取決於編程者本人。有必要
瞭解的是,複合表達式即爲模式間通過使用下述各表達式互相結合起來的表達式:
&& AND : 語句兩邊必須同時匹配爲真。
|| O R:語句兩邊同時或其中一邊匹配爲真。
! 非求逆
11. AND
打印記錄,使其名字爲‘ P. B u n n y且級別爲Ye l l o w,使用表達式( $ 1 = = " P. B u n n y " & &
$ 4 = = " Ye l l o w " ),意爲& &兩邊匹配均爲真。完整命令如下:
12. Or
如果查詢級別爲Ye l l o w或B r o w n,使用或命令。意爲“ | |”符號兩邊的匹配模式之一或全
部爲真。
9.2.6 awk內置變量
a w k有許多內置變量用來設置環境信息。這些變量可以被改變。表9 - 3顯示了最常使用的
一些變量,並給出其基本含義。
表9-3 awk內置變量
A R G C 命令行參數個數
A R G V 命令行參數排列
E N V I R O N 支持隊列中系統環境變量的使用
FILENAME a w k瀏覽的文件名
F N R 瀏覽文件的記錄數
F S 設置輸入域分隔符,等價於命令行- F選項
第9章AWK 介紹73
下載
(續)
N F 瀏覽記錄的域個數
N R 已讀的記錄數
O F S 輸出域分隔符
O R S 輸出記錄分隔符
R S 控制記錄分隔符
A R G C支持命令行中傳入a w k腳本的參數個數。A R G V是A R G C的參數排列數組,其中每
一元素表示爲A R G V [ n ],n爲期望訪問的命令行參數。
E N V I R O N 支持系統設置的環境變量,要訪問單獨變量,使用實際變量名,例如
E N V I R O N [“E D I TO R”] =“Vi”。
F I L E N A M E支持a w k腳本實際操作的輸入文件。因爲a w k可以同時處理許多文件,因此如
果訪問了這個變量,將告之系統目前正在瀏覽的實際文件。
F N R支持a w k目前操作的記錄數。其變量值小於等於N R。如果腳本正在訪問許多文件,
每一新輸入文件都將重新設置此變量。
F S用來在a w k中設置域分隔符,與命令行中- F選項功能相同。缺省情況下爲空格。如果用
逗號來作域分隔符,設置F S = ","。
N F支持記錄域個數,在記錄被讀之後再設置。
O F S允許指定輸出域分隔符,缺省爲空格。如果想設置爲#,寫入O F S = " # "。
O R S爲輸出記錄分隔符,缺省爲新行( / n)。
R S是記錄分隔符,缺省爲新行( / n )。
9.2.7 NF、NR和FILENAME
下面看一看a w k內置變量的例子。
要快速查看記錄個數,應使用N R。比如說導出一個數據庫文件後,如果想快速瀏覽記錄
個數,以便對比於其初始狀態,查出導出過程中出現的錯誤。使用N R將打印輸入文件的記錄
個數。print NR放在E N D語法中。
以下例子中,所有學生記錄被打印,並帶有其記錄號。使用N F變量顯示每一條讀記錄中
有多少個域,並在E N D部分打印輸入文件名。
在從文件中抽取信息時,最好首先檢查文件中是否有記錄。下面的例子只有在文件中至
少有一個記錄時才查詢B r o w n級別記錄。使用A N D複合語句實現這一功能。意即至少存在一
個記錄後,查詢字符串B r o w n,最後打印結果。
74 第二部分文本過濾
下載
N F的一個強大功能是將變量$ P W D的返回值傳入a w k並顯示其目錄。這裏需要指定域分隔
符/。
另一個例子是顯示文件名。
9.2.8 awk操作符
在a w k中使用操作符,基本表達式可以劃分爲數字型、字符串型、變量型、域及數組元素,
前面已經講過一些。下面列出其完整列表。
在表達式中可以使用下述任何一種操作符。
= += *= / = %= ^ = 賦值操作符
? 條件表達操作符
|| && ! 並、與、非(上一節已講到)
~!~ 匹配操作符,包括匹配和不匹配
< <= == != >> 關係操作符
+ - * / % ^ 算術操作符
+ + -- 前綴和後綴
前面已經講到了其中幾種操作,下面繼續講述未涉及的部分。
1. 設置輸入域到域變量名
在a w k中,設置有意義的域名是一種好習慣,在進行模式匹配或關係操作時更容易理解。
一般的變量名設置方式爲n a m e = $ n,這裏n a m e爲調用的域變量名, n爲實際域號。例如設置學
生域名爲n a m e,級別域名爲b e l t,操作爲n a m e = $ 1 ; b e l t s = $ 4。注意分號的使用,它分隔a w k命
令。下面例子中,重新賦值學生名域爲n a m e,級別域爲b e l t s。查詢級別爲Ye l l o w的記錄,並
最終打印名稱和級別。
2. 域值比較操作
有兩種方式測試一數值域是否小於另一數值域。
1) 在B E G I N中給變量名賦值。
2) 在關係操作中使用實際數值。
通常在B E G I N部分賦值是很有益的,可以在a w k表達式進行改動時減少很多麻煩。
使用關係操作必須用圓括號括起來。
下面的例子查詢所有比賽中得分在2 7點以下的學生。
用引號將數字引用起來是可選的,“2 7”、2 7產生同樣的結果。
第9章AWK 介紹75
下載
第二個例子中給數字賦以變量名B A S E L I N E和在B E G I N部分給變量賦值,兩者意義相同。
3. 修改數值域取值
當在a w k中修改任何域時,重要的一點是要記住實際輸入文件是不可修改的,修改的只是
保存在緩存裏的a w k複本。a w k會在變量N R或N F變量中反映出修改痕跡。
爲修改數值域,簡單的給域標識重賦新值,如: $ 1 = $ 1 + 5,會將域1數值加5,但要確保賦
值域其子集爲數值型。
修改M . Ta n s l e y的目前級別分域,使其數值從4 0減爲3 9,使用賦值語句$ 6 = $ 6 - 1,當然在
實施修改前首先要匹配域名。
4. 修改文本域
修改文本域即對其重新賦值。需要做的就是賦給一個新的字符串。在J . Tr o l l中加入字母,
使其成爲J . L . Tr o l l,表達式爲$ 1 = " J . L . Tr o l l ",記住字符串要使用雙秒號( " "),並用圓括號括
起整個語法。
5. 只顯示修改記錄
上述例子均是對一個小文件的域進行修改,因此打印出所有記錄查看修改部分不成問題,
但如果文件很大,記錄甚至超過1 0 0,打印所有記錄只爲查看修改部分顯然不合情理。在模式
後面使用花括號將只打印修改部分。取得模式,再根據模式結果實施操作,可能有些抽象,
現舉一例,只打印修改部分。注意花括號的位置。
6. 創建新的輸出域
在a w k中處理數據時,基於各域進行計算時創建新域是一種好習慣。創建新域要通過其他
域賦予新域標識符。如創建一個基於其他域的加法新域{ $ 4 = $ 2 + $ 3 },這裏假定記錄包含3個域,
則域4爲新建域,保存域2和域3相加結果。
在文件g r a d e . t x t中創建新域8保存域目前級別分與域最高級別分的減法值。表達式爲
‘{ $ 8 = $ 7 - $ 6 }’,語法首先測試域目前級別分小於域最高級別分。新域因此只打印其值大於零
的學生名稱及其新域值。在B E G I N部分加入t a b鍵以對齊報告頭。
76 第二部分文本過濾
下載
當然可以創建新域,並賦給其更有意義的變量名。例如:
7. 增加列值
爲增加列數或進行運行結果統計,使用符號+ =。增加的結果賦給符號左邊變量值,增加
到變量的域在符號右邊。例如將$ 1加入變量t o t a l,表達式爲t o t a l + = $ 1。列值增加很有用。許
多文件都要求統計總數,但輸出其統計結果十分繁瑣。在a w k中這很簡單,請看下面的例子。
將所有學生的‘目前級別分’加在一起,方法是t o t + = $ 6,t o t即爲a w k瀏覽的整個文件的
域6結果總和。所有記錄讀完後,在E N D部分加入一些提示信息及域6總和。不必在a w k中顯
示說明打印所有記錄,每一個操作匹配時,這是缺省動作。
如果文件很大,你只想打印結果部分而不是所有記錄,在語句的外面加上圓括號()即
可。
8. 文件長度相加
在目錄中查看文件時,如果想快速查看所有文件的長度及其總和,但要排除子目錄,使
用ls -l命令,然後管道輸出到a w k,a w k首先剔除首字符爲d(使用正則表達式)的記錄,然後
將文件長度列相加,並輸出每一文件長度及在E N D部分輸出所有文件的長度。
本例中,首先用ls -l命令查看一下文件屬性。注意第二個文件屬性首字符爲d,說明它是
一個目錄,文件長度是第5列,文件名是第9列。如果系統不是這樣排列文件名及其長度,應
適時加以改變。
下面的正則表達式表明必須匹配行首,並排除字符d,表達式爲^ [ ^ d ]。
使用此模式打印文件名及其長度,然後將各長度相加放入變量t o t中。
第9章AWK 介紹77
下載
9.2.9 內置的字符串函數
a w k有許多強大的字符串函數,見表9 - 4。
表9-4 awk內置字符串函數
g s u b ( r, s ) 在整個$ 0中用s替代r
g s u b ( r, s , t ) 在整個t中用s替代r
i n d e x ( s , t ) 返回s中字符串t的第一位置
l e n g t h ( s ) 返回s長度
m a t c h ( s , r ) 測試s是否包含匹配r的字符串
s p l i t ( s , a , f s ) 在f s上將s分成序列a
s p r i n t ( f m t , e x p ) 返回經f m t格式化後的e x p
s u b ( r, s ) 用$ 0中最左邊最長的子串代替s
s u b s t r ( s , p ) 返回字符串s中從p開始的後綴部分
s u b s t r ( s , p , n ) 返回字符串s中從p開始長度爲n的後綴部分
g s u b函數有點類似於s e d查找和替換。它允許替換一個字符串或字符爲另一個字符串或字
符,並以正則表達式的形式執行。第一個函數作用於記錄$ 0,第二個g s u b函數允許指定目標,
然而,如果未指定目標,缺省爲$ 0。
i n d e x(s,t)函數返回目標字符串s中查詢字符串t的首位置。l e n g t h函數返回字符串s字符
長度。m a t c h函數測試字符串s是否包含一個正則表達式r定義的匹配。s p l i t使用域分隔符f s將
字符串s劃分爲指定序列a。s p r i n t函數類似於p r i n t f函數(以後涉及),返回基本輸出格式f m t的
結果字符串e x p。s u b(r,s)函數將用s替代$ 0中最左邊最長的子串,該子串被( r)匹配。
s u b(s,p)返回字符串s在位置p後的後綴。s u b s t r(s,p,n)同上,並指定子串長度爲n。
現在看一看a w k中這些字符串函數的功能。
1. gsub
要在整個記錄中替換一個字符串爲另一個,使用正則表達式格式, /目標模式/,替換模式
/。例如改變學生序號4 8 4 2到4 8 9 9:
2. index
查詢字符串s中t出現的第一位置。必須用雙引號將字符串括起來。例如返回目標字符串
B u n n y中n y出現的第一位置,即字符個數。
3. length
返回所需字符串長度,例如檢驗字符串J . Tr o l l返回名字及其長度,即人名構成的字符個
數。
還有一種方法,這裏字符串加雙引號。
78 第二部分文本過濾
下載
4. match
m a t c h測試目標字符串是否包含查找字符的一部分。可以對查找部分使用正則表達式,返
回值爲成功出現的字符排列數。如果未找到,返回0,第一個例子在A N C D中查找d。因其不
存在,所以返回0。第二個例子在A N C D中查找D。因其存在,所以返回A N C D中D出現的首位
置字符數。第三個例子在學生J . L u l u中查找u。
5. split
使用s p l i t返回字符串數組元素個數。工作方式如下:如果有一字符串,包含一指定分隔
符- ,例如A D2 - K P 9 - J U 2 - L P - 1,將之劃分成一個數組。使用s p l i t,指定分隔符及數組名。此
例中,命令格式爲( " A D 2 - K P 9 - J U 2 - L P - 1 ",p a r t s _ a r r a y," - "),s p l i t然後返回數組下標數,這
裏結果爲4。
還有一個例子使用不同的分隔符。
這個例子中,s p l i t返回數組m y a r r a y的下標數。數組m y a r r a y取值如下:
本章結尾部分講述數組概念。
6. sub
使用s u b發現並替換模式的第一次出現位置。字符串S T R包含‘poped popo pill’,執行下
列s u b命令s u b(/ o p /," o p ",S T R)。模式o p第一次出現時,進行替換操作,返回結果如下:
‘pO Ped pope pill’。
本章文本文件中,學生J . Tr o l l的記錄有兩個值一樣,“目前級別分”與“最高級別分”。只
改變第一個爲2 9,第二個仍爲2 4不動,操作命令爲s u b(/ 2 6 /," 2 9 ",$ 0),只替換第一個出現
2 4的位置。注意J . Tr o l l記錄需存在。
7. substr
s u b s t r是一個很有用的函數。它按照起始位置及長度返回字符串的一部分。例子如下:
上面例子中,指定在域1的第一個字符開始,返回其前面5個字符。
第9章AWK 介紹79
下載
如果給定長度值遠大於字符串長度, a w k將從起始位置返回所有字符,要抽取L Ta n s l - e y
的姓,只需從第3個字符開始返回長度爲7。可以輸入長度9 9,a w k返回結果相同。
s u b s t r的另一種形式是返回字符串後綴或指定位置後面字符。這裏需要給出指定字符串及
其返回字串的起始位置。例如,從文本文件中抽取姓氏,需操作域1,並從第三個字符開始:
還有一個例子,在B E G I N部分定義字符串,在E N D部分返回從第t個字符開始抽取的子
串。
8. 從s h e l l中向a w k傳入字符串
本章開始已經提到過, a w k腳本大多隻有一行,其中很少是字符串表示的。本書大多要求
在一行內完成a w k腳本,這一點通過將變量傳入a w k命令行會變得很容易。現就其基本原理講
述一些例子。
使用管道將字符串s t a n d - b y傳入a w k,返回其長度。
設置文件名爲一變量,管道輸出到a w k,返回不帶擴展名的文件名。
設置文件名爲一變量,管道輸出到a w k,只返回其擴展名。
9.2.10 字符串屏蔽序列
使用字符串或正則表達式時,有時需要在輸出中加入一新行或查詢一元字符。
打印一新行時,(新行爲字符/ n),給出其屏蔽序列,以不失其特殊含義,用法爲在字符
串前加入反斜線。例如使用/ n強迫打印一新行。
如果使用正則表達式,查詢花括號( { }),在字符前加反斜線,如/ / { /,將在a w k中失掉其
特殊含義。
表9 - 5列出a w k識別的另外一些屏蔽序列
表9-5 awk中使用的屏蔽序列
/ b 退格鍵/ t t a b鍵
/ f 走紙換頁/ d d d 八進制值
/ n 新行/ c 任意其他特殊字符,例如/ /爲反斜線符號
/ r 回車鍵
80 第二部分文本過濾
下載
使用上述符號,打印May Day,中間夾t a b鍵,後跟兩個新行,再打印May Day,但這次
使用八進制數1 0 4、1 4 1、1 7 1、分別代表D、a、y。
注意,/ 1 0 4爲D的八進制A S C I I碼,/ 1 4 1爲a的八進制A S C I I碼,等等。
9.2.11 awk輸出函數printf
目前爲止,所有例子的輸出都是直接到屏幕,除了t a b鍵以外沒有任何格式。a w k提供函
數p r i n t f,擁有幾種不同的格式化輸出功能。例如按列輸出、左對齊或右對齊方式。
每一種p r i n t f函數(格式控制字符)都以一個%符號開始,以一個決定轉換的字符結束。
轉換包含三種修飾符。
p r i n t f函數基本語法是p r i n t f([格式控制符],參數),格式控制字符通常在引號裏。
9.2.12 printf修飾符
表9-6 awk printf修飾符
- 左對齊
Wi d t h 域的步長,用0表示0步長
. p r e c 最大字符串長度,或小數點右邊的位數
表9-7 awk printf格式
% c A S C I I字符
% d 整數
% e 浮點數,科學記數法
% f 浮點數,例如(1 2 3 . 4 4)
% g a w k決定使用哪種浮點數轉換e或者f
% o 八進制數
% s 字符串
% x 十六進制數
1. 字符轉換
觀察A S C I I碼中6 5的等價值。管道輸出6 5到a w k。p r i n t f進行A S C I I碼字符轉換。這裏也加
入換行,因爲缺省情況下p r i n t f不做換行動作。
當然也可以按同樣方式使用a w k得到同樣結果。
所有的字符轉換都是一樣的,下面的例子表示進行浮點數轉換後‘ 9 9 9’的輸出結果。整
數傳入後被加了六個小數點。
2. 格式化輸出
第9章AWK 介紹81
下載
打印所有的學生名字和序列號,要求名字左對齊, 1 5個字符長度,後跟序列號。注意/ n
換行符放在最後一個指示符後面。輸出將自動分成兩列。
最好加入一些文本註釋幫助理解報文含義。可在正文前嵌入頭信息。注意這裏使用p r i n t
加入頭信息。如果願意,也可使用p r i n t f。
3. 向一行a w k命令傳值
在查看a w k腳本前,先來查看怎樣在a w k命令行中傳遞變量。
在a w k執行前將值傳入a w k變量,需要將變量放在命令行中,格式如下:
awk 命令變量=輸入文件值
(後面會講到怎樣傳遞變量到a w k腳本中)。
下面的例子在命令行中設置變量A G E等於1 0,然後傳入a w k中,查詢年齡在1 0歲以下的
所有學生。
要快速查看文件系統空間容量,觀察其是否達到一定水平,可使用下面a w k一行腳本。因
爲要監視的已使用空間容量不斷在變化,可以在命令行指定一個觸發值。首先用管道命令將
df -k 傳入a w k,然後抽出第4列,即剩餘可利用空間容量。使用$ 4 ~ / ^ [ 0 - 9 ] /取得容量數值
(1 0 2 4塊)而不是d f的文件頭,然後對命令行與‘ i f ( $ 4 < T R I G G E R )’上變量T R I G G E R中指定
的值進行查詢測試。
在系統中使用df -k命令,產生下列信息:
如果系統中d f輸出格式不同,必須相應改變列號以適應工作系統。
當然可以使用管道將值傳入a w k。本例使用w h o命令, w h o命令第一列包含註冊用戶名,
這裏打印註冊用戶,並加入一定信息。
a w k也允許傳入環境變量。下面的例子使用環境變量L O G N A M E支持當前用戶名。可從
w h o命令管道輸出到a w k中獲得相應信息。
82 第二部分文本過濾
下載
如果r o o t爲當前登錄用戶,輸出如下:
root you are connected to ttyp1
4. awk腳本文件
可以將a w k腳本寫入一個文件再執行它。命令不必很長(儘管這是寫入一個腳本文件的主
要原因),甚至可以接受一行命令。這樣可以保存a w k命令,以使不必每次使用時都需要重新
輸入。使用文件的另一個好處是可以增加註釋,以便於理解腳本的真正用途和功能。
使用前面的幾個例子,將之轉換成a w k可執行文件。像原來做的一樣,將學生目前級別分
相加awk ‘(t o t + = $ 6) END{print "club student total points:" t o t }’ g r a d e . t x t。
創建新文件s t u d e n t _ t o t . a w k,給所有a w k程序加入a w k擴展名是一種好習慣,這樣通過查
看文件名就知道這是一個a w k程序。文本如下:
第一行是! /bin/awk -f。這很重要,沒有它自包含腳本將不能執行。這一行告之腳本系統
中a w k的位置。通過將命令分開,腳本可讀性提高,還可以在命令之間加入註釋。這裏加入頭
信息和結尾的平均值。基本上這是一個一行腳本文件。
執行時,在腳本文件後鍵入輸入文件名,但是首先要對腳本文件加入可執行權限。
系統中運用的帳號覈實程序檢驗數據操作人的數據輸入,不幸的是這個程序有一點錯誤,
或者應該說是“非文本特徵”。如果一個記錄被發現包含一個錯誤,它應該一次只打印一行
第9章AWK 介紹83
下載
“E R R O R *”,但實際上打印了許多這樣的錯誤行。這會給帳號管理員造成誤解,因此需要用
a w k腳本過濾出錯誤行的出現頻率,使得每一個失敗記錄只對應一個錯誤行。
在a w k實施過濾前先看看部分文件:
a w k腳本如下:
a w k過濾結果如下:
5. 在a w k中使用F S變量
如果使用非空格符做域分隔符( F S)瀏覽文件,例如# 或:,編寫這樣的一行命令很容易,
因爲使用F S選項可以在命令行中指定域分隔符。
84 第二部分文本過濾
下載
使用a w k腳本時,記住設置F S變量是在B E G I N部分。如果不這樣做, a w k將會發生混淆,
不知道域分隔符是什麼。
下述腳本指定F S變量。腳本從/ e t c / p a s s w d文件中抽取第1和第5域,通過分號“;”分隔
p a s s w d文件域。第1域是帳號名,第5域是帳號所有者。
6. 向a w k腳本傳值
向a w k腳本傳值與向a w k一行命令傳值方式大體相同,格式爲:
awk script_file var=value input_file
下述腳本對比檢查文件中域號和指定數字。這裏使用了N F變量M A X,表示指定檢查的域
號,使用雙引號將域分隔符括起來,即使它是一個空格。
如果以/ e t c / p a s s w d作輸入文件(p a s s w d文件有7個域),運行上述腳本。參數格式如下:
使用前面一行腳本的例子,將之轉換成a w k腳本如下:
文本包括了比實際命令更多的信息,沒關係,仔細研讀文本後,就可以精確知道其功能
及如何調用它。
不要忘了增加腳本的可執行權限,然後將變量和賦值放在命令行腳本名字後、輸入文件
前執行。
第9章AWK 介紹85
下載
同樣可以使用前面提到的管道命令傳值,下述a w k腳本從d u命令獲得輸入,並輸出塊和字
節數。
爲運行這段腳本,使用d u命令,並管道輸出至a w k腳本。
9.2.13 awk數組
前面講述s p l i t函數時,提到怎樣使用它將元素劃分進一個數組。這裏還有一個例子:
在上面的例子中,s p l i t返回數組m y a r r a y下標數。實際上m y a r r a y數組爲:
數組使用前,不必定義,也不必指定數組元素個數。經常使用循環來訪問數組。下面是
一種循環類型的基本結構:
For (element in array ) print array[element]
對於記錄“ 1 2 3 # 4 5 6 # 6 7 8”,先使用s p l i t函數劃分它,再使用循環打印各數組元素。操作
腳本如下:
數組和記錄
86 第二部分文本過濾
下載
要運行腳本,使用/ d e v / n u l l作爲輸入文件。
上面的例子講述怎樣通過s p l i t函數使用數組。也可以預先定義數組,並使用它與域進行比
較測試,下面的例子中將使用更多的數組。
下面是從空手道數據庫卸載的一部分數據,包含了學生級別及是否是成人或未成年人的
信息,有兩個域,分隔符爲( #),文件如下:
腳本功能是讀文件並輸出下列信息。
1) 俱樂部中Ye l l o w、O r a n g e和R e d級別的人各是多少。
2 ) 俱樂部中有多少成年人和未成年人。
查看文件,也許2 0秒內就會猜出答案,但是如果記錄超過6 0個又怎麼辦呢?這不會很容
易就看出來,必須使用a w k腳本。
首先看看a w k腳本,然後做進一步講解。
第9章AWK 介紹87
下載
B E G I N部分設置F S爲符號#,即域分隔符,因爲要查找Ye l l o w、O r a n g e和R e d三個級別。
然後在腳本中手工建立數組下標對學生做同樣的操作。注意,腳本到此只有下標或元素,並
沒有給數組名本身加任何註釋。初始化完成後, B E G I N部分結束。記住B E G I N部分並沒有文
件處理操作。
現在可以處理文件了。首先給數組命名爲c o l o r,使用循環語句測試域1級別列是否等於數
組元素之一(Ye l l o w、O r a n g e或R e d),如果匹配,依照匹配元素將運行總數保存進數組。
同樣處理數組‘ S e n i o r _ o r _ j u n i o r’,瀏覽域2時匹配操作滿足,運行總數存入j u n i o r或
s e n i o r的匹配數組元素。
E N D部分打印瀏覽結果,對每一個數組使用循環語句並打印它。
注意在打印語句末尾有一個/符號,用來通知a w k(或相關腳本)命令持續到下一行,當
輸入一個很長的命令,並且想分行輸入時可使用這種方法。運行腳本前記住要加入可執行權
限。
9.3 小結
a w k語言學起來可能有些複雜,但使用它來編寫一行命令或小腳本並不太難。本章講述了
a w k的最基本功能,相信大家已經掌握了a w k的基本用法。a w k是s h e l l編程的一個重要工具。
在s h e l l命令或編程中,雖然可以使用a w k強大的文本處理能力,但是並不要求你成爲這方面的
專家。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章