歡迎光臨
每天分享高質量文章

快收藏! 30 分鐘包你學會 AWK

本文大部分內容翻譯自我開始學習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系語言一樣,主要包括 forwhiledo...whilebreakcontinue 陳述句,當然,還有一個 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允許我們自己創建自定義的函式。一個大型的程式可以被劃分為多個函式,每個函式之間可以獨立的開發和測試,提供可重用的代碼。

下麵是用戶自定義函式的基本語法

輸出重定向

重定向運算子

到目前為止,我們所有的程式都是直接顯示資料到了標準輸出流,其實,我們也可以將輸出重定向到檔案。重定向運算子跟在printprintf函式的後面,與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函式關閉命令

美化輸出

到目前為止,我們已經使用過printprintf函式顯示資料到標準輸出,但是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好文請點擊【閱讀原文】

    ↓↓↓

    赞(0)

    分享創造快樂