
本文大部分內容翻譯自我開始學習AWK時看到的一篇英文文章 AWK Tutorial ,覺得對AWK入門非常有幫助,所以對其進行了粗略的翻譯,並對其中部分內容進行了刪減或者補充,希望能為對AWK感興趣的小夥伴提供一份快速入門的教程,幫助小夥伴們快速掌握AWK的基本使用方式,當然,我也是剛開始學習AWK,本文在翻譯或者補充的過程中肯定會有很多疏漏或者錯誤,希望大家能夠幫忙指正。
本文將會持續修正和更新,最新內容請參考我的 GITHUB 上的 程式猿成長計劃 專案,歡迎 Star。
概述
AWK是一門解釋型的程式語言。在文字處理領域它是非常強大的,它的名字來源於它的三位作者的姓氏:Alfred Aho, Peter Weinberger 和 Brian Kernighan。
GNU/Linux釋出的AWK目前由自由軟體基金會(FSF)進行開發和維護,通常也稱它為 GNU AWK。
AWK的型別
下麵是幾個AWK的變體:
-
AWK – 原先來源於 AT & T 實驗室的的AWK
-
NAWK – AT & T 實驗室的AWK的升級版
-
GAWK – 這就是GNU AWK。所有的GNU/Linux釋出版都自帶GAWK,它與AWK和NAWK完全相容
AWK的典型用途
使用AWK可以做很多工,下麵是其中一些
-
文字處理
-
輸出格式化的文字報表
-
執行算數運算
-
執行字串操作等等
工作流
要成為AWK程式設計專家,你需要先知道它的內部實現機制,AWK遵循了非常簡單的工作流 – 讀取,執行和重覆,下圖描述了AWK的工作流。

Read
AWK從輸入流(檔案,管道或者標準輸入)中讀取一行,然後儲存到記憶體中。
Execute
所有的AWK命令都依次在輸入上執行。預設情況下,AWK會對每一行執行命令,我們可以透過提供樣式限制這種行為。
Repeat
處理過程不斷重覆,直到到達檔案結尾。
程式結構
現在,讓我們先學習一下AWK的程式結構。
BEGIN 陳述句塊
BEGIN陳述句塊的語法
BEGIN {awk-commands}
BEGIN陳述句塊在程式開始的使用執行,它只執行一次,在這裡可以初始化變數。BEGIN是AWK的關鍵字,因此它必須為大寫,註意,這個陳述句塊是可選的。
BODY 陳述句塊
BODY陳述句塊的語法
/pattern/ {awk-commands}
BODY陳述句塊中的命令會對輸入的每一行執行,我們也可以透過提供樣式來控制這種行為。註意,BODY陳述句塊沒有關鍵字。
END 陳述句塊
END陳述句塊的語法
END {awk-commands}
END陳述句塊在程式的最後執行,END是AWK的關鍵字,因此必須為大寫,它也是可選的。
讓我們建立一個包含序號,學生姓名,科目名稱和得分的檔案 marks.txt.
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89
下麵的例子中我們將會顯示檔案內容,並且新增每一列的標題

上述程式碼執行後,輸出以下內容

在程式的開始,AWK在BEGIN陳述句中打印出標題。然後再BODY陳述句中,它會讀取檔案的每一行然後執行AWK的print命令將每一行的內容列印到標準輸出。這個過程會一直重覆直到檔案的結尾。
基礎語法
AWK的使用非常簡單,我們可以直接在命令列中執行AWK的命令,也可以從包含AWK命令的文字檔案中執行。
AWK命令列
我們可以使用單引號在命令列中指定AWK命令

AWK程式檔案
我們可以使用指令碼檔案提供AWK命令

AWK標準選項
AWK支援下列命令列標準選項
-v 變數賦值選項
該選項將一個值賦予一個變數,它會在程式開始之前進行賦值,下麵的例子描述了該選項的使用

–dump-variables[=file] 選項
該選項會輸出排好序的全域性變數串列和它們最終的值到檔案中,預設的檔案是 awkvars.out。

–help 選項
列印幫助資訊.

–lint[=fatal] 選項
該選項允許檢查程式的不相容性或者模稜兩可的程式碼,當提供引數 fatal的時候,它會對待Warning訊息作為Error。

–posix 選項
該選項開啟嚴格的POSIX相容。
–profile[=file]選項
該選項會輸出一份格式化之後的程式到檔案中,預設檔案是 awkprof.out。

–traditional 選項
該選項會禁止所有的gawk規範的擴充套件。
–version 選項
輸出版本號

基本使用示例
本部分會講述一些有用的AWK命令和它們的使用示例,所有的例子都是以下麵的文字檔案 marks.txt 為基礎的。

在檔案marks.txt中,第三列包含了科目名,第四列則是得分,上面的例子中,我們只打印出了這兩列,$3 和 $4 代表了輸入記錄中的第三和第四個欄位。
列印所有的行
預設情況下,AWK會打印出所有匹配樣式的行

列印匹配樣式的列
當樣式匹配成功時,預設情況下AWK會列印該行,但是也可以讓它只打印指定的欄位。例如,下麵的例子中,只會打印出匹配樣式的第三和第四個欄位。

任意順序列印

列印超過18個字元的行

內建變數
AWK提供了很多內建的變數,它們在開發AWK指令碼的過程中起著非常重要的角色。
標準AWK變數
ARGC 命令列引數個數
命令列中提供的引數個數

ENVIRON 環境變數
環境變數的關聯陣列

NF 欄位數目

OFS 輸出欄位分隔符
輸出欄位分隔符,預設為空

RSTART
match函式匹配的第一次出現位置

$n
當前行中的第n個欄位

GNU AWK的變數
ARGIND
當前被處理的ARGV的索引

BINMODE
在非POSIX系統上指定對所有的檔案I/O採用二進位制樣式。
ERRORNO
一個代表了getline跳轉失敗或者是close呼叫失敗的錯誤的字串。

FIELDWIDTHS
設定了空格分隔的欄位寬度變數串列的話,GAWK會將輸入解析為固定寬度的欄位,而不是使用FS進行分隔。
IGNORECASE
設定了這個變數的話,AWK會忽略大小寫。

LINT
提供了對–lint選項的動態控制。

運運算元
與其它程式語言一樣,AWK也提供了大量的運運算元。
算數運運算元
算數運運算元不多說,直接看例子,無非就是+-*/%

增減運運算元
自增自減與C語言一致。

賦值運運算元

關係運運算元

邏輯運運算元

三元運運算元

一元運運算元

指數運運算元

字串連線運運算元

陣列成員運運算元

正則運算式運運算元
正則運算式運運算元使用 ~ 和 !~ 分別代表匹配和不匹配。

更多關於正則運算式請看後面的正則運算式部分
正則運算式
AWK在處理正則運算式方面是非常強大的,使用簡單的正則運算式可以處理非常複雜的問題。


陣列
AWK支援關聯陣列,也就是說,不僅可以使用數字索引的陣列,還可以使用字串作為索引,而且數字索引也不要求是連續的。陣列不需要宣告可以直接使用,語法如下:

在AWK中,只支援一維陣列,但是可以透過一維陣列模擬多維,例如我們有一個3×3的三維陣列

流程控制
流程控制陳述句與大多數語言一樣,基本格式如下

迴圈
迴圈操作與其他C系語言一樣,主要包括 for,while,do...while,break,continue 陳述句,當然,還有一個 exit陳述句用於退出指令碼執行。

exit用於退出指令碼,引數為退出的狀態碼,可以透過shell中的$?獲取
函式
內建函式
AWK提供了很多方便的內建函式供程式設計人員使用。由於函式比較多,個人覺得單純看每個函式的使用也沒有什麼實際意義,比較容易遺忘,因此,這裡只簡單的列出常用的一些函式,只需要對其有個印象即可,使用的時候再去 查手冊 效果會更好一些吧。
數學函式
-
atan2(y, x) -
cos(expr) -
exp(expr) -
int(expr) -
log(expr) -
rand -
sin(expr) -
sqrt(expr) -
srand([expr])
字串函式
-
asort(arr [, d [, how] ]) -
asorti(arr [, d [, how] ]) -
gsub(regex, sub, string) -
index(str, sub) -
length(str) -
match(str, regex) -
split(str, arr, regex) -
sprintf(format, expr-list) -
strtonum(str) -
sub(regex, sub, string) -
substr(str, start, l) -
tolower(str) -
toupper(str)
時間函式
-
systime -
mktime(datespec) -
strftime([format [, timestamp[, utc-flag]]])
位元組操作函式
-
and -
compl -
lshift -
rshift -
or -
xor
其它





使用者自定義函式
函式是程式基本的組成部分,AWK允許我們自己建立自定義的函式。一個大型的程式可以被劃分為多個函式,每個函式之間可以獨立的開發和測試,提供可重用的程式碼。
下麵是使用者自定義函式的基本語法

輸出重定向
重定向運運算元
到目前為止,我們所有的程式都是直接顯示資料到了標準輸出流,其實,我們也可以將輸出重定向到檔案。重定向運運算元跟在print和printf函式的後面,與shell中的用法基本一致。

管道
除了將輸出重定向到檔案之外,我們還可以將輸出重定向到其它程式,與shell中一樣,我們可以使用管道運運算元|。

第一次I/O操作使用了|&運運算元,gawk會建立一個到執行其它程式的子行程的雙向管道,print的輸出被寫入到了subprogram的標準輸入,而這個subprogram的標準輸出在gawk中使用getline函式進行讀取。
註意:目前協同行程的標準錯誤輸出將會和gawk的標準錯誤輸出混雜在一起,無法單獨獲取標準錯誤輸出。另外,I/O緩衝可能存在問題,gawk程式會自動的掃清所有輸出到下游的協同行程的管道。但是,如果協同行程沒有掃清其標準輸出的話,gawk將可能會在使用
getline函式從協同行程讀取輸出的時候掛起,這就可能引起死鎖。
我們可以使用close函式關閉雙向管道的to或者from一端,這兩個字串值告訴gawk傳送資料到協同行程完成時或者從協同行程讀取完畢時關閉管道。在使用系統命令sort的時候是這樣做是非常必要的,因為它必須等所有輸出都讀取完畢時才能進行排序。

上例看起來有些複雜,我們逐行分析一下
-
首先,第一行 cmd = “tr [a-z] [A-Z]” 是在AWK中要建立雙向連線的命令
-
第二行的print命令用於為tr命令提供輸入,而
|&用於指出要建立雙向連線 -
第三行用於在上面的陳述句close(cmd, “to”),在執行完成後關閉其to行程
-
第四行 cmd |& getline out使用getline函式儲存輸出到變數out中
-
最後一行使用close函式關閉命令
美化輸出
到目前為止,我們已經使用過print和printf函式顯示資料到標準輸出,但是printf函式實際上要比我們之前使用的情況更加強大得多。該函式是從C語言中借鑒來的,在處理格式化的輸出時非常有用。

格式化輸出標識有
%c,%d,%s等,基本與C語言一致,這裡就不多贅述了。
執行shell命令
在AWK中執行shell命令有兩種方式
-
使用
system函式 -
使用管道
使用system函式
system函式用於執行作業系統命令並且傳回命令的退出碼到awk。

使用管道
如果要執行的命令很多,可以將輸出的命令直接用管道傳遞給“/bin/sh”執行

參考
-
AWK Tutorial
-
The GNU Awk User’s Guide
本文將會持續修正和更新,最新內容請參考我的 GITHUB 上的 程式猿成長計劃 專案,歡迎 Star。
來源:伯樂線上 – mylxsw
《Linux雲端計算及運維架構師高薪實戰班》2018年08月27日即將開課中,120天衝擊Linux運維年薪30萬,改變速約~~~~
*宣告:推送內容及圖片來源於網路,部分內容會有所改動,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。
– END –


更多Linux好文請點選【閱讀原文】哦
↓↓↓
知識星球