Linux中國

awk 實用學習指南

在眾多 Linux 命令中,sedawkgrep 恐怕是其中最經典的三個命令了。它們引人注目或許是由於名字發音與眾不同,也可能是它們無處不在,甚至是因為它們存在已久,但無論如何,如果要問哪些命令很有 Linux 風格,這三個命令是當之無愧的。其中 sedgrep 已經有很多簡潔的標準用法了,但 awk 的使用難度卻相對突出。

在日常使用中,通過 sed 實現字元串替換、通過 grep 實現過濾,這些都是司空見慣的操作了,但 awk 命令相對來說是用得比較少的。在我看來,可能的原因是大多數人都只使用 sed 或者 grep 的一些變化實現某些功能,例如:

$ sed -e 's/foo/bar/g' file.txt
$ grep foo file.txt

因此,儘管你可能會覺得 sedgrep 使用起來更加順手,但實際上它們還有更多更強大的作用沒有發揮出來。當然,我們沒有必要在這兩個命令上鑽研得很深入,但我有時會好奇自己「學習」命令的方式。很多時候我會記住一整串命令「咒語」,而不會去了解其中的運作過程,這就讓我產生了一種很熟悉命令的錯覺,我可以隨口說出某個命令的好幾個選項參數,但這些參數具體有什麼作用,以及它們的相關語法,我都並不明確。

這大概就是很多人對 awk 缺乏了解的原因了。

為使用而學習 awk

awk 並不深奧。它是一種相對基礎的編程語言,因此你可以把它當成一門新的編程語言來學習:使用一些基本命令來熟悉語法、了解語言中的關鍵字並實現更複雜的功能,然後再多加練習就可以了。

awk 是如何解析輸入內容的

awk 的本質是將輸入的內容看作是一個數組。當 awk 掃描一個文本文件時,會把每一行作為一條 記錄 record ,每一條記錄中又分割為多個 欄位 field awk 記錄了各條記錄各個欄位的信息,並通過內置變數 NR(記錄數) 和 NF(欄位數) 來調用相關信息。例如一下這個命令可以查看文件的行數:

$ awk 'END { print NR;}' example.txt
36

從上面的命令可以看出 awk 的基本語法,無論是一個單行命令還是一整個腳本,語法都是這樣的:

模式或關鍵字 { 操作 }

在上面的例子中,END 是一個關鍵字而不是模式,與此類似的另一個關鍵字是 BEGIN。使用 BEGINEND 可以讓 awk 在解析內容前或解析內容後執行大括弧中指定的操作。

你可以使用 模式 pattern 作為過濾器或限定符,這樣 awk 只會對匹配模式的對應記錄執行指定的操作。以下這個例子就是使用 awk 實現 grep 命令在文件中查找「Linux」字元串的功能:

$ awk '/Linux/ { print $0; }' os.txt
OS: CentOS Linux (10.1.1.8)
OS: CentOS Linux (10.1.1.9)
OS: Red Hat Enterprise Linux (RHEL) (10.1.1.11)
OS: Elementary Linux (10.1.2.4)
OS: Elementary Linux (10.1.2.5)
OS: Elementary Linux (10.1.2.6)

awk 會將文件中的每一行作為一條記錄,將一條記錄中的每個單詞作為一個欄位,默認情況下會以空格作為 欄位分隔符 field separator FS)切割出記錄中的欄位。如果想要使用其它內容作為分隔符,可以使用 --field-separator 選項指定分隔符:

$ awk --field-separator ':' '/Linux/ { print $2; }' os.txt
 CentOS Linux (10.1.1.8)
 CentOS Linux (10.1.1.9)
 Red Hat Enterprise Linux (RHEL) (10.1.1.11)
 Elementary Linux (10.1.2.4)
 Elementary Linux (10.1.2.5)
 Elementary Linux (10.1.2.6)

在上面的例子中,可以看到在 awk 處理後每一行的行首都有一個空格,那是因為在源文件中每個冒號(:)後面都帶有一個空格。和 cut 有所不同的是,awk 可以指定一個字元串作為分隔符,就像這樣:

$ awk --field-separator ': ' '/Linux/ { print $2; }' os.txt
CentOS Linux (10.1.1.8)
CentOS Linux (10.1.1.9)
Red Hat Enterprise Linux (RHEL) (10.1.1.11)
Elementary Linux (10.1.2.4)
Elementary Linux (10.1.2.5)
Elementary Linux (10.1.2.6)

awk 中的函數

可以通過這樣的語法在 awk 中自定義函數:

函數名稱(參數) { 操作 }

函數的好處在於只需要編寫一次就可以多次復用,因此函數在腳本中起到的作用會比在構造單行命令時大。同時 awk 自身也帶有很多預定義的函數,並且工作原理和其它編程語言或電子表格一樣。你只需要了解函數需要接受什麼參數,就可以放心使用了。

awk 中提供了數學運算和字元串處理的相關函數。數學運算函數通常比較簡單,傳入一個數字,它就會傳出一個結果:

$ awk 'BEGIN { print sqrt(1764); }'
42

而字元串處理函數則稍微複雜一點,但 GNU awk 手冊中也有充足的文檔。例如 split() 函數需要傳入一個待分割的單一欄位、一個用於存放分割結果的數組,以及用於分割的 定界符 delimiter

例如前面示例中的輸出內容,每條記錄的末尾都包含了一個 IP 地址。由於變數 NF 代表的是每條記錄的欄位數量,剛好對應的是每條記錄中最後一個欄位的序號,因此可以通過引用 NF 將每條記錄的最後一個欄位傳入 split() 函數:

$ awk --field-separator ': ' '/Linux/ { split($NF, IP, "."); print "subnet: " IP[3]; }' os.txt
subnet: 1
subnet: 1
subnet: 1
subnet: 2
subnet: 2
subnet: 2

還有更多的函數,沒有理由將自己限制在每個 awk 代碼塊中。你可以在終端中使用 awk 構建複雜的管道,也可以編寫 awk 腳本來定義和使用你自己的函數。

下載電子書

使用 awk 本身就是一個學習 awk 的過程,即使某些操作使用 sedgrepcuttr 命令已經完全足夠了,也可以嘗試使用 awk 來實現。只要熟悉了 awk,就可以在 Bash 中自定義一些 awk 函數,進而解析複雜的數據。

下載我們的這本電子書(需註冊)學習並開始使用 awk 吧!

via: https://opensource.com/article/20/9/awk-ebook

作者:Seth Kenlon 選題:lujun9972 譯者:HankChow 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國