本文大部分內容翻譯自我開始學習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好文請點選【閱讀原文】哦
↓↓↓