序
很多人把大把的時間花在一些簡單、機械的數據處理上——改改數據格式、看看是否規整、找找特定的條目、加總數字、打印報表,諸如此類的小事。這些重復枯燥的瑣事本是程序語言的強項,但真要用C、Pascal這樣的標準編程語言去解決卻也有苦難言。
你需要一種能在寥寥數行之內解決這類問題的編程語言,awk就有此奇功。用awk編程就像在寫規則說明:問,遇到這樣的數據怎么辦?答,如此這般。這“問”即為欲處理數據之匹配模式;這“答”即是找到所需數據后,awk采取的動作。awk每讀入一行就會逐項查找那些模式,一旦匹配,執行其后的動作。模式既可以是正則表達式,也可以是用于字串、數字、域(field)、變量、序列元素(array element)間比較的關系運算符(comparison operation)。awk對動作沒有太多的限制。描述動作的語言有點像C,但是不用聲明,字串也數字也是內置的數據類型。
awk會自動掃描輸入文件并將之拆分成域。很多事情,比如拆分輸入、存儲管理、初始數據,都由awk代勞。這也是awk寫出的程序更短小的原因。awk很適合來做這些數據處理。寫上一兩行awk程序,執行,解決問題,然后丟棄。實際上,awk作為通用的編程工具,完全可以取代某些專用程序。
awk很適合來開發程序原型,因為它表達簡潔、操作方便。從很少的幾行代碼開始,不斷修改直至達到目標,同時還可以嘗試不同的設計。因為程序短小,沒有什么負擔,即便設計方向錯了也容易扭正。而且只要設計正確,用其他語言來改寫awk程序也很簡單。
本書的框架
本書的初衷是介紹awk以及如何高效的使用awk。第一章(An AWK Tutorial)告訴你如何起步。內容很簡單,讀過幾頁你就可以開始寫一些能用得上的程序了。這章的例子很短,主要是與awk交互。
第二章(The AWK Language)開始系統地介紹整個awk語言。比起第一章,這一章的例子就多了,而且開始變得又長又臭_,就像讀說明書一樣。所以,第一次讀的時候你可能會跳過去。
本書余下的部分還收錄了很多示例,從中你不僅可以看到awk應用之廣泛,還可以了解其精髓。之所以選擇這些示例,有些是很正式的用法,有些只是幫助理解,還有些僅僅是因為好玩。
第三章(Data Processing)著重介紹了檢索、變換、化簡和數據驗證,這也是設計awk的初衷。本章的最后,還討論了如何處理大數據(比如地址簿)。
awk很適合管理個人的小型數據庫。第四章(Reports and Databases)討論了如何從數據庫生成報表、如何搭建簡易的關系型數據庫(relational database system)、如何用查詢語言(query language)在多個文件中查找。
awk處理文本就像其他語言操作數字一樣得心應手。文本處理是awk的專長。第五章(Processing Words)描述了如何生成文本,這在文檔預處理中用處不小。我們還把寫本書時用到的索引程序也收錄進來了。
第六章(Little Languages)是關于“袖珍語言”,也就是專門用于某個狹窄領域的特定語言。用awk來寫一些小型的轉換程序很方便,因為它有很多在詞法或是表管理(table-management)層面上支持轉換的運算符。在這一章會看到一個(awk寫的)匯編程序、一門圖像語言和幾個計算器。
awk中變量不用聲明,存儲管理也很容易,所以很適合表述某些算法。awk寫出的程序和偽代碼很相似,更重要的是它還可以運行。第七章(Experiments with Algorithms)著重探討了如何用awk來考察算法,從測試到執行效率(,我們都有涉及)。我們用awk實現了幾個排序算法,以及一個Unix版的make程序。
第八章(Epilog)記敘了awk之所以為awk的歷史原因,并就性能和擴展給出了建議。
附錄一(A AWK Summary)小結了這門語言;附錄二(Answers to Selected Exercises)給出了部分習題答案。
你可以從從頭開始讀起,試試運行你自己遇到的小程序??焖賿哌^第二章,重點看看小結和表(table),不要急于陷入細節之中。后面的章節幾乎相互獨立,不必在意順序,完全可以憑興趣決定。
書中的示例
對本書的示例,收錄時我們有幾個考慮。第一,當然是展示怎么用好awk。我們想盡可能地涵蓋awk的十八般武器,尤其鐘愛關聯序列(associative array)和正則表達式類具有awk特色(譯注:awk較早引入了關聯序列的概念,待考證)的工具。
第二個考慮是展現awk的廣泛使用。從數據查詢到電路設計,從數值分析到圖像處理,從程序編譯到系統管理,從非程序員的啟蒙語言到軟件工程的課程實踐,隨處可見awk的身影。我們希望書中羅列的各式應用能使你們受到更多的啟發。
第三個考慮是為了說明計算操作的無處不在。這本書選取的例子涉及很廣,有關系型數據庫、簡易的匯編程序和解釋程序、畫圖語言、一個描述awk子集的遞歸下降解析程序、基于make的文件更新程序等等。但所有的例子都試圖用一小段awk程序,以便于理解的方式,去揭示事物運作的本質。
此外,我們還盡可能地介紹一些設計程序的方法。比如awk支持得很好的快速原型方法,以及不那么直觀的分而治之策略:把一個大工程分割成一堆小問題,每一個都只著眼問題的某一方面。還有開發寫程序的程序,即領域語言。定義好用戶接口,并提出合理的實現。雖然這些思想都是用awk來體現的,但它們普遍適用,值得每個程序員重視。
書中所有的例子都可以運行。我們曾想保證程序不含錯誤,但與其把精力放在怎么處理所有的非法輸入上,或者為了確保正確而放棄功能擴展,還不如集中精力好好琢磨怎么把事理說透。
AWK的演化
1977年,筆者想試試Unix下的grep和sed能不能像處理數字那樣處理文本,所以設計實現了最初的awk。這也得益于我們對正則表達式和可編程編輯器(programmable editor)的興趣。雖然我們把awk定位于解決日常任務,但它很快被用戶用到大項目之中。有些大項目需要一些設計之外的特性,所以1985年我們在最初版本的基礎上開發了一個更強大的版本。
最重要的新特性是用戶可以自定義函數了。另外還增強了動態正則表達式(dynamic regular expression)、文本替換和模式匹配函數;增加了一些內置函數和內置變量;添加了一些新的操作符和語句;支持多文件輸入和命令行參數。錯誤管理也有所改進。第一章我只會用到原始版本的特性;后面章節的例子會涉及到一些新特性。
我們用的這個awk版本是Unix System V Release 3.1。這個版本的awk源代碼可以從AT&T下的Unix工具軟件發布系統上獲得。??
因為awk是在Unix下開發的,它的一些特性只在Unix下才能施展,有些我們的例子中也會提到。另外,有些Unix工具,比如sort,只有Unix版本。拋開這些限制,awk在大部分環境中都應用得很不錯,包括MS-DOS。
當然,awk并不完美。它不夠規整(“it has its share of irregularities, omissions, and just plain bad ideas”這句真不會翻),甚至有時還慢得令人發指。但同時它也能出色地滿足各種需求。awk給了我們很大幫助,希望你也能同樣受惠于它。
致謝
我們深深地受惠于那些對本書的草稿給出過評論和建議的朋友們。這里,我們要特別感謝Jon Bentley(譯注:《編程珠璣》那位神作者?),他的激情多年來一直在賦予我們靈感。Jon貢獻了很多awk使用、教學方面的想法、經驗,甚至是代碼。他非常仔細地審閱了多部手稿。還有Doug McIlroy,他無與倫比的天才極大地影響了我們,使我們從框架到內容都進行了很多修改。還有很多朋友對手稿給出了極富建設意義的評論,Susan Aho、Jaap Akkerhuis、Lorinda Cherry、Chris Fraser、Eric Grosse、Riccardo Gusella、Bob Herbst、Mark Kernighan、John Linderman、Bob Martin(譯注:難道是Martin大神?)、Howard Moscovitz、Gerard Schmitt、Don Swartwout、Howard Trickey、Peter van Eijk、Chris Van Wyk、Mihalis Yannakakis。謝謝你們!
Alfred V. Aho
Brian W. Kernighan
Peter J. Weinberger