AWK

AWK是一種優良的文字處理工具，Linux及Unix環境中現有的功能最強大的資料處理引擎之一。這種程式設計及資料操作語言的最大功能取決於一個人所擁有的知識。AWK提供了極其強大的功能：可以進行正則表示式的匹配，樣式裝入、流控制、數學運算子、程序控制語句甚至於內建的變數和函式。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上AWK的確擁有自己的語言：AWK程式設計語言，三位建立者已將它正式定義為“樣式掃描和處理語言”。它允許建立簡短的程式，這些程式讀取輸入檔案、為資料排序、處理資料、對輸入執行計算以及生成報表，還有無數其他的功能。gawk是AWK的GNU版本。最簡單地說，AWK是一種用於處理文字的程式語言工具。AWK在很多方面類似於Unix shell程式語言，儘管AWK具有完全屬於其本身的語法。它的設計思想SNOBOL4、sed、Marc Rochkind設計的有效性語言、語言工具yacc和lex，當然還從C語言中獲取了一些優秀的思想。在最初創造AWK時，其目的是用於文字處理，並且這種語言的基礎是，只要在輸入資料中有模式匹配，就執行一系列指令。該實用工具掃描檔案中的每一行，查詢與命令列中所給定內容相匹配的模式。如果發現匹配內容，則進行下一個程式設計步驟。如果找不到匹配內容，則繼續處理下一行。AWK程式結構.AWK是一種處理文字檔案的語言。它將檔案作為記錄序列處理。在一般情況下，檔案內容的每行都是一個記錄。每行內容都會被分割成一系列的域，因此，我們可以認為一行的第一個詞為第一個域，第二個詞為第二個，以此類推。AWK程式是由一些處理特定模式的語句塊構成的。AWK一次可以讀取一個輸入行。對每個輸入行，AWK直譯器會判斷它是否符合程式中出現的各個模式，並執行符合的模式所對應的動作。AWK程式是由一系列模式--動作對組成的，寫做其中codice_1表示AWK在資料中查詢的內容，而codice_2是在找到匹配內容時所執行的一系列命令。輸入行被分成了一些記錄：記錄預設由換行符分割，因此輸入會按照行進行分割。程式使用給定的條件一個個的測試每條記錄，並執行測試透過的條件所對應的codice_2。codice_1和codice_2都可以省略不寫。無codice_1預設匹配全部的記錄；而無codice_2則是列印原始記錄。簡單的AWK表示式之外，codice_1可以是codice_9或codice_10；這兩種條件對應的codice_2分別是讀取所有的記錄之前和之後。同時，如codice_12的條件表示符合條件codice_13和codice_14的記錄及其之間的部分。除了一般的，C語言風格的算術和邏輯運算子外，AWK允許運算子"~"，用來測試正則表示式是否可以與一字串匹配。作為語法糖，沒有"~"運算子的正則表示式會被用來對當前記錄進行測試，相當於codice_15。AWK命令.AWK命令即為前文例子中以"action"指代的語句。AWK命令可以包括函式呼叫，變數賦值，計算，及/或各項的組合。標準AWK提供了許多內建函式；其部分實現則可能提供了更多的內建函式。同時，AWK的部分實現支援動態連結庫，使得其可以支援更多的函式。便利起見，下述例子中可能省略大括號。"print"命令."print "命令用於輸出文字。其輸出的文字總是以"輸出記錄分隔符"分割的，其預設值為換行符。該命令的最簡形式為：雖然域的符號("$X ")可能類似於某些語言中的變數，但在AWK中，它們指代的是當前記錄的域。另外，"$0"是指整個記錄。事實上，命令codice_16和codice_17的效果是相同的。"print"命令也可以顯示變數、計算、函式呼叫的結果：print 3+2print foobar(3)print foobar(variable)print sin(3-2)其輸出可以重定向到File:print "expression" &gt; "file name"或重定向到管道：print "expression" | "command"內建變數.AWK的內建變數包括域變數，例如$1, $2, $3，以及$0。這些變數給出了記錄中域的內容。內建變數也包括一些其他變數：變數和語法.變數名可以是語言關鍵字外的，只包含大小寫拉丁字母，數字和下劃線分隔的。語句無需以分號結尾。另外，註釋是以“#”開頭的。使用者定義函式.函式是以與C語言類似的方式定義的，以關鍵字codice_21開頭，後面跟函式名稱，引數列表和函式體。# 示例函式function add_three (number) {return number + 3上面的函式可以如此呼叫：print add_three(36) # 輸出39函式可以擁有其私有變數。其私有變數可以寫在引數列表之後，因為這些值會在呼叫函式時被忽略。通常可以在引數列表中引數和私有變數之間加入一些空格，用以區別“真正的”引數和私有變數。函式宣告中，函式名和括號間可以有任意空格，但在呼叫時二者必須緊鄰。樣例-{}-程式.Hello World.AWK的"hello world"程式為：注意此處無需寫出codice_22語句，因為唯一的模式是codice_9。輸出長度大於80的行.輸出長度大於80字元的行。注意模式的預設行為是輸出當前行。length($0) &gt; 80輸出單詞計數.對輸入中的單詞進行計數，然後輸出行數，單詞數和字元數。w += NFc += length + 1由於沒有提供模式，輸入的全部行都可以匹配該模式，因此對每行都會執行預定操作。注意codice_24的含義等同於codice_25。計算最後一個單詞的和.codice_26是數值codice_18的累加，codice_18是每條記錄中的最後一個域，codice_29檔案結束時，codice_10模式得到了匹配，因此可以輸出codice_26。然而，在沒有輸入行的情況下，codice_26會沒有值，從而導致沒有輸出。因此，對其加0可以使AWK在這種情況下對其賦值，從而得到一個數值。這種方法是將字串強制轉化為數值的慣用法。如此處理之後，若程式輸入為空檔案，可以得到“0”作為輸出，而不是一個空行。匹配輸入行中的範圍.$ yes Wikipedia | awk 'NR % 4 == 1, NR % 4 == 3 { printf "%6d %s\n", NR, $0 }' | sed 7q1 Wikipedia2 Wikipedia3 Wikipedia5 Wikipedia6 Wikipedia7 Wikipedia9 Wikipediayes命令重複輸入其引數前為假。codice_46命令則是用於擷取其前7行輸出，防止codice_47命令一直執行下去。若codice_48命令可用的話，這行命令的效果和codice_49相同。若範圍模式的第一部分永遠為真，例如設定為“1”，可以用來使該範圍從輸入的最開始開始。類似的，若第二部分總是為假，例如“0”，則該範圍的結束即為輸入的結束。命令/^--cut here--$/, 0會輸出從符合正則表示式“^--cut here--$”開始的輸入行，也即從只包含“--cut here--”的行開始，直到輸入的結束。計算詞頻.使用關聯陣列計算詞頻：BEGIN {FS="[^a-zA-Z]+"{for(i=1; i&lt;=NF; ++i)words[tolower($i)]++END {for(i in words)print i, words[i]codice_9塊設定域分隔符為任意非字母字元。值得注意的是，分隔符不僅可以是字串，也可以是正則表示式。然後，程式對每個輸入行執行相同的操作。在此，對每個域，我們累加其小寫形式出現的次數。最後，在codice_10塊中，我們輸出單詞及其出現的次數。程式碼for(i in words)建立了一個遍歷關聯陣列中元素的迴圈，其中，codice_52會被設為對應的鍵。這一點和多數語言不同，而和Objective-C 2.0中的codice_53語法相似。這樣的語法允許以簡單的方式遍歷陣列，從而輸出這些單詞。另外，codice_54函式是One True awk的附加函式。從命令匹配模式.這個程式可以以多種不同形式出現。第一個使用Bourne shell指令碼來完成大部分工作。這也是最短的一個方法：$ cat grepinawkpattern=$1shiftawk '/'$pattern'/ { print FILENAME ":" $0 }' $*awk命令中的codice_55並沒有為引號所保護。在這裡，模式可以檢查輸入行是否與之匹配。codice_57變數則包含了當前的檔名。awk沒有顯式的字串連線運算子；與BASH相似，只需簡單的將字串並列即可。codice_35則會輸出原始的輸入行。也有另外的方法來完成同樣的任務。下面的指令碼直接在awk中訪問環境變數。$ cat grepinawkpattern=$1shiftawk '$0 ~ ENVIRON["pattern"] { print FILENAME ":" $0 }' $*這個指令碼用到了陣列codice_59，一個One True awk中引入的量。其作用類似與POSIX標準中的getenv (3)函式。這個指令碼先建立了一個名為codice_1的環境變數，其值為指令碼的第一個引數，然後讓awk在其餘的引數所代表的檔案內尋找該模式。codice_61是用於檢查其兩個運算元是否匹配的運算子；其逆則為codice_62。注意正則表示式也屬於普通的字串，可以儲存於變數中。下面的方法則採用了在命令列對變數賦值的方法，即在awk的引數中寫入一個變數的值：$ cat grepinawkpattern=$1shiftawk '$0 ~ pattern { print FILENAME ":" $0 }' "pattern=$pattern" $*最後，這種方法是純awk的，無需shell的幫助，也無需知道太多關於awk指令碼實現的細節；但這種方法的指令碼有點長：BEGIN {pattern = ARGV[1]for (i = 1; i &lt; ARGC; i++) # 去除第一個引數ARGV[i] = ARGV[i + 1]ARGC—if (ARGC == 1) { # 模式是唯一引數，因此強制從標準輸入讀取ARGC = 2ARGV[1] = "-"codice_9塊的作用不僅僅是提取出第一個引數，也防止第一個引數在codice_9塊結束後直接被解釋為輸入檔案。codice_65，輸入引數的數量永遠是不小於1的，因為codice_66是執行指令碼的命令名，通常是codice_67。另外，codice_68永遠是空串。對於其中的codice_69塊，它表明若沒有指定輸入檔案，awk會直接讀取標準輸入流。也即awk 'prog'也可以工作，因為程式中已經將codice_65置為了2；若該值為1，則awk會認為沒有檔案需要讀取而直接退出。同時，若需從標準輸入讀取資料，需要將檔名顯式的指定為codice_72。自包含的AWK指令碼.與許多其他的程式語言相似，可以利用“shebang”語法構建自包含的awk指令碼。例如，一個名為codice_73，可以輸出“Hello, world!”的UNIX命令可以透過建立內容如下，名為codice_73的檔案來完成：#!/usr/bin/awk -fcodice_75引數告訴awk將該檔案作為awk的程式檔案，然後即可執行該程式。