這個系列的第二篇,咱們會學習字段,記錄和一些很是有用的 Awk 變量。php
Awk 有好幾個變種:最先的 awk
,是 1977 年 AT&T 貝爾實驗室所創。它還有一些重構版本,例如 mawk
、nawk
。在大多數 Linux 發行版中能見到的,是 GNU awk,也叫 gawk
。在大多數 Linux 發行版中,awk
和 gawk
都是指向 GNU awk 的軟連接。輸入 awk
,調用的是同一個命令。GNU awk 用戶手冊中,能看到 awk
和 gawk
的所有歷史。html
這一系列的第一篇文章 介紹了 awk
命令的基本格式:node
$ awk [選項] '模式 {動做}' 輸入文件
複製代碼
awk
是一個命令,後面要接選項 (好比用 -F
來定義字段分隔符)。想讓 awk
執行的部分須要寫在兩個單引號之間,至少在終端中須要這麼作。在 awk
命令中,爲了進一步強調你想要執行的部分,能夠用 -e
選項來突出顯示(但這不是必須的):linux
$ awk -F, -e '{print $2;}' colours.txt
yellow
blue
green
[...]
複製代碼
awk
將輸入數據視爲一系列記錄,一般是按行分割的。換句話說,awk
將文本中的每一行視做一個記錄。每一記錄包含多個字段。一個字段由字段分隔符分隔開來,字段是記錄的一部分。git
默認狀況下,awk
將各類空白符,如空格、製表符、換行符等視爲分隔符。值得注意的是,在 awk
中,多個空格將被視爲一個分隔符。因此下面這行文本有兩個字段:github
raspberry red
複製代碼
這行也是:正則表達式
tuxedo black
複製代碼
其餘分隔符,在程序中不是這麼處理的。假設字段分隔符是逗號,以下所示的記錄,就有三個字段。其中一個字段可能會是 0 個字節(假設這一字段中不包含隱藏字符)編程
a,,b
複製代碼
awk
命令的程序部分是由一系列規則組成的。一般來講,程序中每一個規則佔一行(儘管這不是必須的)。每一個規則由一個模式,或一個或多個動做組成:bash
模式 { 動做 }
複製代碼
在一個規則中,你能夠經過定義模式,來肯定動做是否會在記錄中執行。模式能夠是簡單的比較條件、正則表達式,甚至二者結合等等。app
這個例子中,程序只會顯示包含單詞 「raspberry」 的記錄:
$ awk '/raspberry/ { print $0 }' colours.txt
raspberry red 99
複製代碼
若是沒有文本符合模式,該動做將會應用到全部記錄上。
而且,在一條規則只包含模式時,至關於對整個記錄執行 { print }
,所有打印出來。
Awk 程序本質上是數據驅動的,命令執行結果取決於數據。因此,與其餘編程語言中的程序相比,它仍是有些區別的。
每一個字段都有指定變量,但針對字段和記錄,也存在一些特殊變量。NF
變量,能存儲 awk
在當前記錄中找到的字段數量。其內容可在屏幕上顯示,也可用於測試。下面例子中的數據,來自上篇文章文本:
$ awk '{ print $0 " (" NF ")" }' colours.txt
name color amount (3)
apple red 4 (3)
banana yellow 6 (3)
[...]
複製代碼
awk
的 print
函數會接受一系列參數(能夠是變量或者字符串),並將它們拼接起來。這就是爲何在這個例子裏,每行結尾處,awk
會以一個被括號括起來的整數表示字段數量。
另外,除了統計每一個記錄中的字段數,awk
也統計輸入記錄數。記錄數被存儲在變量 NR
中,它的使用方法和其餘變量沒有任何區別。例如,爲了在每一行開頭顯示行號:
$ awk '{ print NR ": " $0 }' colours.txt
1: name color amount
2: apple red 4
3: banana yellow 6
4: raspberry red 3
5: grape purple 10
[...]
複製代碼
注意,寫這個命令時能夠不在 print
後的多個參數間添加空格,儘管這樣會下降可讀性:
$ awk '{print NR": "$0}' colours.txt
複製代碼
爲了讓輸出結果時格式更靈活,你可使用 awk
的 printf()
函數。 它與 C、Lua、Bash 和其餘語言中的 printf
相相似。它也接受以逗號分隔的格式參數。參數列表須要寫在括號裏。
$ printf 格式, 項目1, 項目2, ...
複製代碼
格式這一參數(也叫格式符)定義了其餘參數如何顯示。這一功能是用格式修飾符實現的。%s
輸出字符,%d
輸出十進制數字。下面的 printf
語句,會在括號內顯示字段數量:
$ awk 'printf "%s (%d)\n",$0,NF}' colours.txt
name color amount (3)
raspberry red 4 (3)
banana yellow 6 (3)
[...]
複製代碼
在這個例子裏,%s (%d)
肯定了每一行的輸出格式,$0,NF
定義了插入 %s
和 %d
位置的數據。注意,和 print
函數不一樣,在沒有明確指令時,輸出不會轉到下一行。出現轉義字符 \n
時纔會換行。
這篇文章中出現的全部 awk
代碼,都在 Bash 終端中執行過。面對更復雜的程序,將命令放在文件(腳本)中會更容易。-f FILE
選項(不要和 -F
弄混了,那個選項用於字段分隔符),可用於指明包含可執行程序的文件。
舉個例子,下面是一個簡單的 awk 腳本。建立一個名爲 example1.awk
的文件,包含如下內容:
/^a/ {print "A: " $0}
/^b/ {print "B: " $0}
複製代碼
若是一個文件包含 awk
程序,那麼在給文件命名時,最好寫上 .awk
的擴展名。 這樣命名不是強制的,但這麼作,會給文件管理器、編輯器(和你)一個關於文件內容的頗有用的提示。
執行這一腳本:
$ awk -f example1.awk colours.txt
A: raspberry red 4
B: banana yellow 6
A: apple green 8
複製代碼
一個包含 awk
命令的文件,在最開頭一行加上釋伴 #!
,就能變成可執行腳本。建立一個名爲 example2.awk
的文件,包含如下內容:
#!/usr/bin/awk -f
#
# 除了第一行,在其餘行前顯示行號
#
NR > 1 {
printf "%d: %s\n",NR,$0
}
複製代碼
能夠說,腳本中只有一行,大多數狀況下沒什麼用。但在某些狀況下,執行一個腳本,比記住,而後打一條命令要容易的多。一個腳本文件,也提供了一個記錄命令具體做用的好機會。以 #
號開頭的行是註釋,awk
會忽略它們。
給文件可執行權限:
$ chmod u+x example2.awk
複製代碼
執行腳本:
$ ./example2.awk colours.txt
2: apple red 4
2: banana yellow 6
4: raspberry red 3
5: grape purple 10
[...]
複製代碼
將 awk
命令放在腳本文件中,有一個好處就是,修改和格式化輸出會更容易。在終端中,若是能用一行執行多條 awk
命令,那麼輸入多行,才能達到一樣效果,就顯得有些多餘了。
你如今已經足夠了解,awk
是如何執行指令的了。如今你應該能編寫複雜的 awk
程序了。試着編寫一個 awk 腳本,它須要: 至少包括一個條件模式,以及多個規則。若是你想使用除 print
和 printf
之外的函數,能夠參考在線 gawk 手冊。
下面這個例子是個很好的切入點:
#!/usr/bin/awk -f
#
# 顯示全部記錄 除了出現如下狀況
# 若是第一個記錄 包含 「raspberry」
# 將 「red」 替換成 「pi」
$1 == "raspberry" {
gsub(/red/,"pi")
}
{ print }
複製代碼
試着執行這個腳本,看看輸出是什麼。接下來就看你本身的了。
這一系列的下一篇文章,將會介紹更多,能在更復雜(更有用!) 腳本中使用的函數。
這篇文章改編自 Hacker Public Radio 系列,一個技術社區博客。
via: opensource.com/article/19/…
做者:Seth Kenlon 選題:lujun9972 譯者:wenwensnow 校對:wxy