awk 實用學習指南
在眾多 Linux 命令中,sed
、awk
和 grep
恐怕是其中最經典的三個命令了。它們引人注目或許是由於名字發音與眾不同,也可能是它們無處不在,甚至是因為它們存在已久,但無論如何,如果要問哪些命令很有 Linux 風格,這三個命令是當之無愧的。其中 sed
和 grep
已經有很多簡潔的標準用法了,但 awk
的使用難度卻相對突出。
在日常使用中,通過 sed
實現字元串替換、通過 grep
實現過濾,這些都是司空見慣的操作了,但 awk
命令相對來說是用得比較少的。在我看來,可能的原因是大多數人都只使用 sed
或者 grep
的一些變化實現某些功能,例如:
$ sed -e 's/foo/bar/g' file.txt
$ grep foo file.txt
因此,儘管你可能會覺得 sed
和 grep
使用起來更加順手,但實際上它們還有更多更強大的作用沒有發揮出來。當然,我們沒有必要在這兩個命令上鑽研得很深入,但我有時會好奇自己「學習」命令的方式。很多時候我會記住一整串命令「咒語」,而不會去了解其中的運作過程,這就讓我產生了一種很熟悉命令的錯覺,我可以隨口說出某個命令的好幾個選項參數,但這些參數具體有什麼作用,以及它們的相關語法,我都並不明確。
這大概就是很多人對 awk
缺乏了解的原因了。
為使用而學習 awk
awk
並不深奧。它是一種相對基礎的編程語言,因此你可以把它當成一門新的編程語言來學習:使用一些基本命令來熟悉語法、了解語言中的關鍵字並實現更複雜的功能,然後再多加練習就可以了。
awk 是如何解析輸入內容的
awk
的本質是將輸入的內容看作是一個數組。當 awk
掃描一個文本文件時,會把每一行作為一條 記錄 ,每一條記錄中又分割為多個 欄位 。awk
記錄了各條記錄各個欄位的信息,並通過內置變數 NR
(記錄數) 和 NF
(欄位數) 來調用相關信息。例如一下這個命令可以查看文件的行數:
$ awk 'END { print NR;}' example.txt
36
從上面的命令可以看出 awk
的基本語法,無論是一個單行命令還是一整個腳本,語法都是這樣的:
模式或關鍵字 { 操作 }
在上面的例子中,END
是一個關鍵字而不是模式,與此類似的另一個關鍵字是 BEGIN
。使用 BEGIN
或 END
可以讓 awk
在解析內容前或解析內容後執行大括弧中指定的操作。
你可以使用 模式 作為過濾器或限定符,這樣 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
會將文件中的每一行作為一條記錄,將一條記錄中的每個單詞作為一個欄位,默認情況下會以空格作為 欄位分隔符 (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()
函數需要傳入一個待分割的單一欄位、一個用於存放分割結果的數組,以及用於分割的 定界符 。
例如前面示例中的輸出內容,每條記錄的末尾都包含了一個 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
的過程,即使某些操作使用 sed
、grep
、cut
、tr
命令已經完全足夠了,也可以嘗試使用 awk
來實現。只要熟悉了 awk
,就可以在 Bash 中自定義一些 awk
函數,進而解析複雜的數據。
下載我們的這本電子書(需註冊)學習並開始使用 awk
吧!
via: https://opensource.com/article/20/9/awk-ebook
作者:Seth Kenlon 選題:lujun9972 譯者:HankChow 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive