使用awk進行進階文本處理 awk 是一款設計用於資料流的工具。它頗為流行的原因在於可以對列和行進行操作。awk有很多內建的功能,比如數組,函數等,這是它和C語言的相同之處。
(1)預備知識 awk的指令碼的結構基本如下所示:
$ awk 'BEGIN{print "start"} pattern {comands} END {print "end"}' file
awk命令也可以從stdin中讀取。 awk指令碼通常由3部分組成。BEGIN,END和帶模式比對選項的常見語句塊。這3個部分都是可選項,在指令碼中可以省略任意部分。
(2)實戰演練 以下awk指令碼被包含在單引號或雙引號之間:
$ awk 'BEGIN {statement}{statements} END {end statements}'
也可以使用:
$awk "BEGIN {statements} {statements} END {end statments}"
例如:
$ awk 'BEGIN {i=0} {i++} END{print i}' filename
或者
$ awk "BEGIN {i=0}{i++} END {print i}" filename
(3)工作原理 awk命令的工作方式如下所注。 (1)執行BEGIN{ commands}語句塊中的語句。 (2)從文本或stdin中讀取一行,然後執行pattern{commands}. 重複這個過程,直到檔案全部被讀取完畢。 (3)當讀至輸入資料流末尾時,執行END{commands}語句塊。 BEGIN 語句塊在awk開始從輸入資料流中讀取行之前被執行。這是一個可選的語句塊,諸如變數初始化,列印輸出表格的表頭等語句通常都可以寫入BEGIN語句塊中。 END語句塊和BEGIN語句塊類似。END語句塊在awk從輸入資料流中讀取玩所有的行之後即被立即執行。像列印所有行的分析結果這類匯總資訊,都是在END語句塊中實現的常見任務(例如:在比較過所有的行之後,列印出最大數)。它也是一個可選的語句塊。 最終要的部分就是pattern語句塊中的通用命令。這個語句塊同樣是可選的,如果不提供該語句塊,則預設執行{print},即列印所讀取的每一行。awk對於每一行,都會執行這個語句塊,這就像一個用來讀取行的while迴圈,在迴圈體中提供了相應的語句。 沒讀取一行,awk就會檢查該行和提供的樣式是否匹配。樣式本身可以是Regex,條件陳述式以及航匹配範圍。如果當前行匹配該樣式,則執行{}中的語句。 樣式是可選的。如果沒有提供樣式,那麼awk就認為所有的行都是匹配的,並執行{}中的語句。 來看例子:
(4)補充內容
awk命令具有豐富的特性。要想洞悉awk編程的精妙之處,首先應該熟悉awk重要的選項和功能,讓我們來看看awk的一些重要特性。 (a):以下是一些用於awk的一些特殊變數。 NR:表示記錄數量,在執行過程中對應於當前行號。 NF:表示欄位數量,在執行過程中對於當前行的欄位數。 $0:這個變數包含執行過程中當前行的常值內容。 $1:這個變數包含第一個欄位的常值內容。 $2:這個變數包含第二個欄位的常值內容。 例如:
我們可以用print $NF列印一行中的最後一個欄位,用$(NF-1)列印倒數第二個欄位,其他欄位依次類推即可。
awk的printf()函數的文法和C語言中的同名函數一樣,我們也可以使用這個函數來代替print。 再來看awk的一些基本用法,列印每一行的第2和第3個欄位:
$awk '{print $2,$3}' file
要統計檔案的行數,使用下面的命令:
$awk 'END{print NR}' file
這裡只使用了END語句塊,每讀入一行,awk會將NR更新為對應的行號。當到達最後一行時,NR中的值就是最後一行的行號了。
awk通常預設讀取一個檔案的所有行,如果只是想讀特定行的內容,就可以使用getline函數,有時候,我們需要從BEGIN語句塊中讀取第一行。 文法:getline var。變數var就包含了特定行的內容。如果調用不帶參數的getline,我們可以用$0,$1,$2訪問文字檔的內容。 例如:
此外,我們還可以使用過濾模式對awk處理的行進行過濾例如 $ awk 'NR<5' # 行號小於5的行 $ awk 'NR==1,NR==4' # 行號在1到5之間的行 $ awk '/linux/' #包含樣式的行(可以使用Regex來指定) $ awk '!/linux/' # 不包含包含模式的為linux的行
(b) 設定欄位界限符 預設的欄位定界符是空格。我麼也可以用-F “delimiter” 明確指定一個定界符:
$ awk -F: '{print $NF}' /etc/passwd
或者
$ awk 'BEGIN {FS=":"} {print $NF}' /etc/passwd
在BEGIN語句中則可以用FS=“delimiter” 設定輸出欄位的定界符。 (c) 在下面的代碼中,echo 會產生一個空白行。變數cmdout包含命令grep root /etc/passwd的輸出,該命令會列印出包含root的行。 將命令的輸出結果讀入變數output的文法如下:
$ "command" | getline output
例如:
$ echo | awk '{"grep root /etc/passwd | getline cmdout; print cmdout"}'
通過使用getline,我們將外部shell命令的輸出讀入輸入變數cmdout。
awk支援以文本作為索引的關聯陣列。
(d)在awk中使用迴圈 在awk中更可以使用for迴圈,其格式如下: for(i=0;i<10;i++) {print $i;} 或者 for(i in array) {print array[i]}