寫在最開始
相比于sed,awk就顯得強(qiáng)大多了载矿。如果說sed是輕巧的山地摩托限书,那awk就是裝甲坦克虫蝶,分分鐘把sed碾碎。awk的復(fù)雜性和高功能性在于:
- 支持?jǐn)U展正則語(yǔ)法
- 語(yǔ)法規(guī)則更豐富和復(fù)雜倦西,大量?jī)?nèi)置變量和靈活自定義變量
- 輸出控制舒適能真,定制型極高
- 邏輯、流程扰柠、內(nèi)置函數(shù)功能齊全
總之a(chǎn)wk已經(jīng)不能用命令來形容了粉铐,awk可以說是一門語(yǔ)言,專門為行數(shù)據(jù)處理而生卤档,其高效性和機(jī)動(dòng)性不言而喻蝙泼。
記錄和域
awk把輸入行進(jìn)行了結(jié)構(gòu)化處理,通過制定分隔字符(用內(nèi)置變量FS指定)劝枣,把輸入行(記錄)分成若干個(gè)域汤踏,如下所示:
# input.txt
zhangsanfeng 70 1.87 wudang
zhangwuji 20 1.85 mingjiao
zhouzhiruo 18 1.65 emei
yuanzhen 40 1.73 shaolin
上面的文件中的每一行都是一條記錄,單獨(dú)拿出來一條記錄時(shí)舔腾,又分為4個(gè)域溪胶,分別指代了:名字,年齡稳诚,身高哗脖,幫派,在awk命令中可以用$1 $2 $3 $4來引用每個(gè)域扳还,用$0來表示這條記錄(原汁原味才避,保留原來的所有字符),有了這些鋪墊普办,我們就可以更方便的對(duì)每個(gè)域進(jìn)行判斷工扎、計(jì)算、輸出衔蹲。
默認(rèn)情況下分隔符是空格 TAB 或其以任意數(shù)量(至少1個(gè))、任意次序的組合呈础,即多個(gè)空格會(huì)被認(rèn)為是一個(gè)分隔符舆驶。
輸出和格式化
awk的輸出方式和C語(yǔ)言幾乎一樣,語(yǔ)法和符號(hào)也幾乎一致而钞∩沉總結(jié)起來有以下幾點(diǎn):
- 用print輸出時(shí),輸出變量如果用逗號(hào)分隔臼节,那么輸出的變量間默認(rèn)為一個(gè)空格符撬陵。
- 用print輸出時(shí)珊皿,默認(rèn)最后會(huì)輸出一個(gè)換行符。
- 用print輸出時(shí)巨税,輸出變量用空格分隔蟋定,那么輸出變量間相互緊鄰。
- 用printf輸出時(shí)草添,輸出格式完全由自己控制驶兜,最后也不會(huì)自動(dòng)輸出換行。
我們就上面的input.txt來進(jìn)行一點(diǎn)展示远寸。
圖1.1中我么用逗號(hào)分隔要輸出的變量$1 $2 $3 $4抄淑,輸出結(jié)果自動(dòng)會(huì)用空格符來分隔,如圖1.2所示驰后,不用逗號(hào)分隔輸出結(jié)果就不會(huì)有分隔肆资,而緊鄰在一起。
如圖1.3所示灶芝,我們?cè)诘?個(gè)域和第3個(gè)域間插入一個(gè)逗號(hào)郑原,在第3個(gè)域和第4個(gè)域間插入一個(gè)下劃線,在記錄的結(jié)尾插入換行符监署,都能直觀的在結(jié)果中展示颤专。圖1.4中展示了更漂亮的輸出控制,符號(hào)-用于控制該域左對(duì)齊輸出(默認(rèn)右對(duì)齊輸出)钠乏,符號(hào)-后面的數(shù)字表示該域至少占的字符寬度(多了往后排栖秕,少了用空格補(bǔ)滿),符號(hào).和格式化符%f搭配晓避,用于輸出保留多少位的小數(shù)(會(huì)四舍五入)簇捍。
除了以上的格式化控制符,還有如下俏拱,僅把他列出來暑塑,不做一一分析。
%c:ASCII字符
%e:科學(xué)技術(shù)輸出
%o:八進(jìn)制輸出
%x:十六進(jìn)制輸出
可以使用的變量類型
同sed一樣锅必,awk中變量也沒有類型事格,也有兩個(gè)值:整數(shù)值和字符值。我把a(bǔ)wk中所有變量分為幾類來分別說明:
- 普通變量(自定義變量)
在說明普通變量前搞隐,先來講一下awk的基本結(jié)構(gòu)驹愚。如下所示:
BEGIN {#這個(gè)左花括號(hào)必須和END在同一行,別問劣纲,問就規(guī)定逢捺,讀入數(shù)據(jù)前執(zhí)行一次。
}
{
# 對(duì)于每條記錄癞季,都要經(jīng)過這個(gè)主體
}
END {#這個(gè)左花括號(hào)必須和END在同一行劫瞳,別問倘潜,問就規(guī)定,處理完所有數(shù)據(jù)后執(zhí)行一次志于。
}
由上面可以得知涮因,awk執(zhí)行的時(shí)候,大致可以分為三個(gè)階段:BEGIN恨憎,主體蕊退,END。BEGIN最先執(zhí)行憔恳,END最后執(zhí)行瓤荔,且都只執(zhí)行一次。主體部分對(duì)于每行記錄都要執(zhí)行一次钥组。
自定義變量推薦放在BEGIN中定義输硝,這樣比較清晰。如下所示程梦,計(jì)算所有人的年齡的平均值点把。
上圖的total就屬于自定義變量,使用名字就可以直接引用屿附。至于上面的NR就是我們接下來要講的內(nèi)置變量了郎逃。
- 內(nèi)置變量
除了可以自定變量,awk實(shí)際還內(nèi)置了很多變量挺份,一來方便用戶使用褒翰,二來,awk自己執(zhí)行的時(shí)候也需要頻繁用到這些變量匀泊,所以在定義自己的變量時(shí)优训,命名注意別和內(nèi)置變量相同。內(nèi)置變量的使用上和普通變量毫無(wú)差別各聘。主要有如下常用的內(nèi)置變量:
$0 1 2...:引用記錄的域
FILENAME:記錄來自哪個(gè)文件
FNR:瀏覽文件的記錄數(shù)
NR:當(dāng)前記錄數(shù)揣非,好像和FNR一樣,number of record
FS:域分隔符躲因,默認(rèn)空格或TAB或其任意組合早敬,field separation
OFS:輸出分隔符,默認(rèn)空格大脉,output field separation
NF:當(dāng)前記錄中的域數(shù)量搁嗓,number of field
ARGC:命令行參數(shù)個(gè)數(shù)
ARGV:命令行參數(shù)存放的數(shù)組,從0起
如下圖所示:域分隔符被設(shè)置為字符h箱靴,輸出分隔符為___,第一條記錄:
z angsanfeng 70 1.87 wudang
被分隔為兩個(gè)部分荷愕,所以在輸出$3的時(shí)候沒有任何東西衡怀。第三條記錄:
z ouz iruo 18 1.65 emei
被分隔為三個(gè)部分棍矛,輸出的時(shí)候,每個(gè)部分用OFS=___連接抛杨。
- 數(shù)組
awk中的數(shù)組的索引可以是字符串够委,也可以是數(shù)字,并且如果數(shù)字09和字符串"09"索引到的是不同元素怖现。其實(shí)awk中的數(shù)組更像鍵值可以是任意類型的map茁帽。awk中提供了一種訪問順序未知的數(shù)組遍歷方式:
for (i in arr)
{
#do something,i is the key屈嗤,not the value
}
if ("zhangsanfeng" in arr)
{
#do something
}
更多情況潘拨,我們用數(shù)組是用來處理字符串,比如在函數(shù)split中饶号,對(duì)記錄進(jìn)行分割后铁追,分割的字段就存放在數(shù)組中,下標(biāo)從1起茫船。
- 命令行參數(shù)
除了內(nèi)置變量和自定義變量琅束,用戶還可以通過命令行來傳遞參數(shù)給腳本,如下所示:
數(shù)據(jù)處理函數(shù)
- gsub:替換字符串
- length:返回字符串的長(zhǎng)度
- match:檢測(cè)是否包含匹配式