awk是一種編程語言,用于在linux/unix下對文本和數(shù)據(jù)進(jìn)行處理。數(shù)據(jù)可以來自標(biāo)準(zhǔn)輸入(stdin)、一個或多個文件,或其它命令的輸出。它支持用戶自定義函數(shù)和動態(tài)正則表達(dá)式等先進(jìn)功能,是linux/unix下的一個強大編程工具。它在命令行中使用,但更多是作為腳本來使用。awk有很多內(nèi)建的功能,比如數(shù)組、函數(shù)等,這是它和C語言的相同之處,靈活性是awk最大的優(yōu)勢。
awk 基本結(jié)構(gòu)
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
一個awk腳本通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊3部分組成,這三個部分是可選的。任意一個部分都可以不出現(xiàn)在腳本中,腳本通常是被單引號或雙引號中,例如:
awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
awk 的工作原理
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
- 第一步:執(zhí)行BEGIN{ commands }語句塊中的語句;
- 第二步:從文件或標(biāo)準(zhǔn)輸入(stdin)讀取一行,然后執(zhí)行pattern{ commands }語句塊,它逐行掃描文件,從第一行到最后一行重復(fù)這個過程,直到文件全部被讀取完畢。
- 第三步:當(dāng)讀至輸入流末尾時,執(zhí)行END{ commands }語句塊。
BEGIN語句塊在awk開始從輸入流中讀取行之前被執(zhí)行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中。
END語句塊在awk從輸入流中讀取完所有的行之后即被執(zhí)行,比如打印所有行的分析結(jié)果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊。
Pattern語句塊中的通用命令是最重要的部分,它也是可選的。如果沒有提供pattern語句塊,則默認(rèn)執(zhí)行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執(zhí)行該語句塊。
root@ubuntu:~# cat cats.txt | awk 'BEGIN{ print "Start" } { print } END{ print "End" }'
Start
This is my cat
my cat's name is betty
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam
End
當(dāng)使用不帶參數(shù)的print時,它就打印當(dāng)前行,當(dāng)print的參數(shù)是以逗號進(jìn)行分隔時,打印時則以空格作為定界符。在awk的print語句塊中雙引號是被當(dāng)作拼接符使用,例如:
root@ubuntu:~# echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3; }'
v1 v2 v3
雙引號拼接使用
root@ubuntu:~# echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1"="var2"="var3; }'
v1=v2=v3
awk 內(nèi)置變量
說明:[A][N][P][G]表示第一個支持變量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
$n 當(dāng)前記錄的第n個字段,比如n為1表示第一個字段,n為2表示第二個字段。
$0 這個變量包含執(zhí)行過程中當(dāng)前行的文本內(nèi)容。
[N] ARGC 命令行參數(shù)的數(shù)目。
[G] ARGIND 命令行中當(dāng)前文件的位置(從0開始算)。
[N] ARGV 包含命令行參數(shù)的數(shù)組。
[G] CONVFMT 數(shù)字轉(zhuǎn)換格式(默認(rèn)值為%.6g)。
[P] ENVIRON 環(huán)境變量關(guān)聯(lián)數(shù)組。
[N] ERRNO 最后一個系統(tǒng)錯誤的描述。
[G] FIELDWIDTHS 字段寬度列表(用空格鍵分隔)。
[A] FILENAME 當(dāng)前輸入文件的名。
[P] FNR 同NR,但相對于當(dāng)前文件。
[A] FS 字段分隔符(默認(rèn)是任何空格)。
[G] IGNORECASE 如果為真,則進(jìn)行忽略大小寫的匹配。
[A] NF 表示字段數(shù),在執(zhí)行過程中對應(yīng)于當(dāng)前的字段數(shù)。
[A] NR 表示記錄數(shù),在執(zhí)行過程中對應(yīng)于當(dāng)前的行號。
[A] OFMT 數(shù)字的輸出格式(默認(rèn)值是%.6g)。
[A] OFS 輸出字段分隔符(默認(rèn)值是一個空格)。
[A] ORS 輸出記錄分隔符(默認(rèn)值是一個換行符)。
[A] RS 記錄分隔符(默認(rèn)是一個換行符)。
[N] RSTART 由match函數(shù)所匹配的字符串的第一個位置。
[N] RLENGTH 由match函數(shù)所匹配的字符串的長度。
[N] SUBSEP 數(shù)組下標(biāo)分隔符(默認(rèn)值是34)。
例子:
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}'
Line No:1, No of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3
Line No:2, No of fields:3 $0=line2 f4 f5 $1=line2 $2=f4 $3=f5
Line No:3, No of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7
使用print $NF可以打印出一行中的最后一個字段,使用$(NF-1)則是打印倒數(shù)第二個字段,其他以此類推:
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print $NF}'
f3
f5
f7
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print $NF}'
f3
f5
f7
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print $NF-1}'
-1
-1
-1
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print $(NF-1)}'
f2
f4
f6
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print $NF"-1"}'
f3-1
f5-1
f7-1
root@ubuntu:~# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print $NF,-1}'
f3 -1
f5 -1
f7 -1
統(tǒng)計文中的行數(shù)
root@ubuntu:~# awk 'END{ print NR }' cats.txt
8
文本中各行數(shù)字相加
root@ubuntu:~# seq 5 | awk 'BEGIN{ sum=0; print "總和:" } { print $1"+"; sum+=$1 } END{ print "等于"; print sum }'
總和:
1+
2+
3+
4+
5+
等于
15
awk 使用外部變量
root@ubuntu:~# var1="aaa"
root@ubuntu:~# var2="bbb"
root@ubuntu:~# echo | awk '{print v1,v2}' v1=$var1 v2=$var2
aaa bbb
root@ubuntu:~# awk '{print v1,v2}' v1=$var1 v2=$var2 cats.txt
aaa bbb
aaa bbb
aaa bbb
aaa bbb
aaa bbb
aaa bbb
aaa bbb
aaa bbb