AWK 是一種優良的工具，Linux 及 Unix 環境中現有的功能最強大的資料處理引擎之一。這種程式設計及資料操作語言（其名稱得自於它的創始人阿爾佛雷德艾侯、彼得溫伯格和布萊恩柯林漢姓氏的首個字母）的最大功能取決於一個人所擁有的知識。AWK 提供了極其強大的功能：可以進行正則表示式的匹配，樣式裝入、流控制、數學運算子、程序控制語句甚至於內建的變數和函式。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上 AWK 的確擁有自己的語言：AWK 程式設計語言，三位建立者已將它正式定義為 樣式掃描和處理語言。它允許建立簡短的程式，這些程式讀取輸入檔案、為資料排序、處理資料、對輸入執行計算以及生成報表，還有無數其他的功能。gawk 是 AWK 的 GNU 版本。 最簡單地說，AWK 是一種用於處理文字的程式語言工具。AWK 在很多方面類似於 Unix shell 程式語言，儘管 AWK 具有完全屬於其本身的語法。它的設計思想來源於 SNOBOL4、sed、Marc Rochkind 設計的有效性語言、語言工具 yacc 和 lex，當然還從 C 語言中獲取了一些優秀的思想。在最初創造 AWK 時，其目的是用於文字處理，並且這種語言的基礎是，只要在輸入資料中有模式匹配，就執行一系列指令。該實用工具掃描檔案中的每一行，查詢與命令列中所給定內容相匹配的模式。如果發現匹配內容，則進行下一個程式設計步驟。如果找不到匹配內容，則繼續處理下一行。 AWK 程式結構 AWK 程式是由一系列模式 動作對組成的，寫做 pattern action 其中 pattern 表示 AWK 在資料中查詢的內容，而 action 是在找到匹配內容時所執行的一系列命令。輸入行被分成了一些記錄：記錄預設由換行符分割，因此輸入會按照行進行分割。程式使用給定的條件一個個的測試每條記錄，並執行測試透過的條件所對應的 action。pattern 和 action 都可以省略不寫。無 pattern 預設匹配全部的記錄；而無 action 則是列印原始記錄。簡單的 AWK 表示式之外，pattern 可以是 BEGIN 或 END；這兩種條件對應的 action 分別是讀取所有的記錄之前和之後。同時，如 pattern1 pattern2 的條件表示符合條件 pattern1 和 pattern2 的記錄及其之間的部分。 除了一般的，C 語言風格的算術和邏輯運算子外，AWK 允許運算子～，用來測試正則表示式是否可以與一字串匹配。作為語法糖，沒有～運算子的正則表示式會被用來對當前記錄進行測試，相當於 regexp 0。 AWK 命令 AWK 命令即為前文例子中以 action 指代的語句。AWK 命令可以包括函式呼叫，變數賦值，計算，及 或各項的組合。標準 AWK 提供了許多內建函式；其部分實現則可能提供了更多的內建函式。同時，AWK 的部分實現支援動態連結庫，使得其可以支援更多的函式。 便利起見，下述例子中可能省略大括號。 print 命令 print 命令用於輸出文字。其輸出的文字總是以 輸出記錄分隔符（Output record separator ORS）分割的，其預設值為換行符。該命令的最簡形式為： print：會輸出當前記錄的內容。在 AWK 中，記錄會被分割成 域，它們可以被分別顯示或使用： print 1：顯示當前記錄的第 1 個域 print 1 3：顯示當前記錄的第 1 和第 3 個域，並以預定義的輸出域分隔符（Output field separator OFS）分隔，其預設值為一個空格符 雖然域的符號 X 可能類似於某些語言中的變數（例如 PHP 和 perl），但在 AWK 中，它們指代的是當前記錄的域。另外，0 是指整個記錄。事實上，命令 print 和 print 0 的效果是相同的。 print 命令也可以顯示變數、計算、函式呼叫的結果： print 32 print foobar 3 print foobar variable print sin 32 其輸出可以重定向到 File print expression file name 或重定向到管道： print expression command 內建變數 AWK 的內建變數包括域變數，例如 1、2、3 以及 0。這些變數給出了記錄中域的內容。 內建變數也包括一些其他變數： NR：已輸入記錄的條數。 NF：當前記錄中域的個數。記錄中最後一個域可以以 NF 的方式引用。 FILENAME：當前輸入檔案的檔名。 FS：域分隔符，用於將輸入記錄分割成域。其預設值為 空白字元，即空格和製表符。FS 可以替換為其它字元，從而改變域分隔符。 RS：當前的 記錄分隔符。預設狀態下，輸入的每行都被作為一個記錄，因此預設記錄分隔符是換行符。 OFS：輸出域分隔符，即分隔 print 命令的引數的符號。其預設值為空格。 ORS：輸出記錄分隔符，即每個 print 命令之間的符號。其預設值為換行符。 OFMT：輸出數字格式（Format for numeric output），其預設值為 6g。 變數和語法 變數名可以是語言關鍵字外的，只包含大小寫拉丁字母，數字和下劃線（_）的任意字。而運算子 、、、 則分別代表加、減、乘、除。簡單的將兩個變數（或字串常量）放在一起，則會將二者串接為一個字串。若二者間至少有一個是常量，則中間可以不加空格；但若二者均為變數，中間必須包括空格。字串常量是以雙引號分隔的。語句無需以分號結尾。另外，註釋是以 開頭的。 使用者定義函式 函式是以與 C 語言類似的方式定義的，以關鍵字 function 開頭，後面跟函式名稱，引數列表和函式體。 示例函式 function add_three number return number 3 上面的函式可以如此呼叫： print add_three 36 輸出 39 函式可以擁有其私有變數。其私有變數可以寫在引數列表之後，因為這些值會在呼叫函式時被忽略。通常可以在引數列表中引數和私有變數之間加入一些空格，用以區別 真正的 引數和私有變數。 函式宣告中，函式名和括號間可以有任意空格，但在呼叫時二者必須緊鄰。 樣例 程式 Hello World AWK 的 hello world 程式為： BEGIN print Hello world 注意此處無需寫出 exit 語句，因為唯一的模式是 BEGIN。 輸出長度大於 80 的行 輸出長度大於 80 字元的行。注意模式的預設行為是輸出當前行。 length 0 80 輸出單詞計數 對輸入中的單詞進行計數，然後輸出行數，單詞數和字元數（類似 wc）。 w NF c length 1 END print NR w c 由於沒有提供模式，輸入的全部行都可以匹配該模式，因此對每行都會執行預定操作。注意 wNF 的含義等同於 w w NF。 計算最後一個單詞的和 s NF END print s 0 s 是數值 NF 的累加，NF 是每條記錄中的最後一個域，NF（沒有 ）是當前行中域的數量。例如一個域數為 4 的行中 NF 相當於 4。事實上， 是一個具有最高優先順序的一元運算子。（若一行沒有域，則有 NF 為 0，而 NF 相當於 0，是整行，在這種情況下，要麼是空串，要麼只有空白符，因此其數值為 0。） 檔案結束時，END 模式得到了匹配，因此可以輸出 s。然而，在沒有輸入行的情況下，s 會沒有值，從而導致沒有輸出。因此，對其加 0 可以使 AWK 在這種情況下對其賦值，從而得到一個數值。這種方法是將字串強制轉化為數值的慣用法（反之，與空串連線則是將數值強制轉換為字串的方法，例如 s ）。如此處理之後，若程式輸入為空檔案，可以得到 0 作為輸出，而不是一個空行。 匹配輸入行中的範圍 yes Wikipedia awk NR 4 1 NR 4 3 printf 6d sn NR 0 sed 7q 1 Wikipedia 2 Wikipedia 3 Wikipedia 5 Wikipedia 6 Wikipedia 7 Wikipedia 9 Wikipedia yes 命令重複輸入其引數（預設則是輸出 y）。在這裡，我們讓該命令輸出 Wikipedia。動作塊則輸出帶行號的內容。printf 函式可以模擬標準 C 中的 printf 函式，其效果與前述的 print 函式類似。而符合模式的行是這樣產生的：NR 是記錄的編號，也就是 AWK 正在處理行的行號（從 1 開始）。 是取餘數運算子。因此，NR 4 1 對第 1、5、9 等行為真。類似的，NR 4 3 對 3、7、11 等行為真。範圍模式在其第一部分匹配（例如對第 1 行）之前為假，並在第二部分匹配（例如第 3 行）之前為真。然後，再在第二次匹配上其第一部分（例如第 5 行）前為假。sed 命令則是用於擷取其前 7 行輸出，防止 yes 命令一直執行下去。若命令可用的話，這行命令的效果和 head n7 相同。 若範圍模式的第一部分永遠為真，例如設定為 1，可以用來使該範圍從輸入的最開始開始。類似的，若第二部分總是為假，例如 0，則該範圍的結束即為輸入的結束。命令 cut here 0 會輸出從符合正則表示式 cut here 開始的輸入行，也即從只包含 cut here 的行開始，直到輸入的結束。 計算詞頻 使用關聯陣列計算詞頻： BEGIN FSazAZ for i1 iNF i words tolower i END for i in words print i words i BEGIN 塊設定域分隔符為任意非字母字元。值得注意的是，分隔符不僅可以是字串，也可以是正則表示式。然後，程式對每個輸入行執行相同的操作。在此，對每個域，我們累加其小寫形式出現的次數。最後，在 END 塊中，我們輸出單詞及其出現的次數。程式碼 for i in words 建立了一個遍歷關聯陣列中元素的迴圈，其中，i 會被設為對應的鍵。這一點和多數語言不同，而和 ObjectiveC 20 中的 forin 語法相似。這樣的語法允許以簡單的方式遍歷陣列，從而輸出這些單詞。另外，tolower 函式是 One True awk（見下文）的附加函式。 從命令匹配模式 這個程式可以以多種不同形式出現。第一個使用 Bourne shell 指令碼來完成大部分工作。這也是最短的一個方法： cat grepinawk pattern1 shift awk pattern print FILENAME 0 awk 命令中的 pattern 並沒有為引號所保護。在這裡，模式可以檢查輸入行（0）是否與之匹配。FILENAME 變數則包含了當前的檔名。awk 沒有顯式的字串連線運算子；與 bash 相似，只需簡單的將字串並列即可。0 則會輸出原始的輸入行。 也有另外的方法來完成同樣的任務。下面的指令碼直接在 awk 中訪問環境變數。 cat grepinawk pattern1 shift awk 0 ENVIRON pattern print FILENAME 0 這個指令碼用到了陣列 ENVIRON，一個 One True awk 中引入的量。其作用類似與 POSIX 標準中的函式。這個指令碼先建立了一個名為 pattern 的環境變數，其值為指令碼的第一個引數，然後讓 awk 在其餘的引數所代表的檔案內尋找該模式。 是用於檢查其兩個運算元是否匹配的運算子；其逆則為！～。注意正則表示式也屬於普通的字串，可以儲存於變數中。 下面的方法則採用了在命令列對變數賦值的方法，即在 awk 的引數中寫入一個變數的值： cat grepinawk pattern1 shift awk 0 pattern print FILENAME 0 patternpattern 最後，這種方法是純 awk 的，無需 shell 的幫助，也無需知道太多關於 awk 指令碼實現的細節（而在命令列對變數賦值的方法可能與 awk 的實現相關）；但這種方法的指令碼有點長： BEGIN pattern ARGV 1 for i 1 i ARGC i 去除第一個引數 ARGV i ARGV i 1 ARGCif ARGC 1 模式是唯一引數，因此強制從標準輸入讀取 ARGC 2 ARGV 1 0 pattern print FILENAME 0 BEGIN 塊的作用不僅僅是提取出第一個引數，也防止第一個引數在 BEGIN 塊結束後直接被解釋為輸入檔案。ARGC，輸入引數的數量永遠是不小於 1 的，因為 ARGV 0 是執行指令碼的命令名，通常是 awk。另外，ARGV ARGC 永遠是空串。對於其中的 if 塊，它表明若沒有指定輸入檔案，awk 會直接讀取標準輸入流（stdin）。也即 awk prog 也可以工作，因為程式中已經將 ARGC 置為了 2；若該值為 1，則 awk 會認為沒有檔案需要讀取而直接退出。同時，若需從標準輸入讀取資料，需要將檔名顯式的指定為 。 自包含的 AWK 指令碼 與許多其他的程式語言相似，可以利用 shebang 語法構建自包含的 awk 指令碼。 例如，一個名為 helloawk，可以輸出 Hello world 的 UNIX 命令可以透過建立內容如下，名為 helloawk 的檔案來完成： usrbinawk f BEGIN print Hello world f 引數告訴 awk 將該檔案作為 awk 的程式檔案，然後即可執行該程式。 參見 sed Unix shell Perl PowerShell 參考文獻 外部連結 gawk 主頁 aaa the Amazing Awk Assembler by Henry Spencer Awk 教學 Category1977 年軟體 Category 指令碼語言 Category 模式匹配程式語言 Category 面向文字程式語言 CategoryUnix 文字處理實用工具 CategoryUnix SUS2008 實用工具 Category 模式匹配程式語言