本人的CSDN博客地址
https://blog.csdn.net/u013332124/article/details/82974759
一、awk 介紹
awk是linux上一款強大的文本分析工具,它可以將文件逐行的讀入,然后用分割符分割開來,再對分割的各個部分進行處理。awk分割的各個部分叫做域,默認的分割符是空格和制表符??梢酝ㄟ^-F來指定分割符。
awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。
二、使用姿勢
主要語法
awk [參數(shù)] 'pattern{action}'
awk的使用看起來比較復(fù)雜,但是掌握好它的語法后,其實也很簡單。
和大多數(shù)的命令一樣,awk可以指定一些參數(shù),也可以不傳任何參數(shù)。awk具體支持哪些參數(shù)讀者可以通過man awk查看相關(guān)幫助文檔。這里就不多做介紹。
在參數(shù)后面跟著一個單引號括起來的執(zhí)行語句,其中pattern表示過濾規(guī)則,支持正則表達式和邏輯表達式。如果pattern涉及多個條件,可以用 && 和 || 來關(guān)聯(lián),分別表示與和或。pattern可以不填,表示不過濾任何數(shù)據(jù)。
pattern后面根據(jù)一個花括號括起來的真正的執(zhí)行語句,比如 print $1 表示輸出分割后的第一個域。action{}可以有多個語句,以;號隔開。如果缺失action則表示輸出一整行的內(nèi)容。和{print}以及{print $0}效果一樣
使用示例
假設(shè)有一段文本test.txt,有2個用逗號隔開的列,分別表示姓名、年齡。
jack,18
nick,24
joe,19
hack,19
輸出所有人的名字
awk -F , '{print $1}' test.txt
-F ,表示用逗號作為分割符,之后pattern為空,action則為{print $1}。awk執(zhí)行后,每一行都會分割成兩列,之后輸出第一列的數(shù)據(jù)。其中2則表示第二列的數(shù)據(jù),以此類推,$n則表示第n列的數(shù)據(jù)。要注意的是,$0表示的是這一整行的數(shù)據(jù)。
輸出年齡小于20歲,并且名字中帶有ck內(nèi)容的人(整行正則匹配)
awk -F , '/ck/ && $2 < 20{print}' test.txt
上面用兩個斜杠//圍起來的就是正則表達式,awk會對每行進行正則匹配,匹配不上的就不會進行處理。
由于直接使用//匹配的是整行數(shù)據(jù),所以如果我們的需求是要找名字中帶有ck內(nèi)容的人的話,語句就不是很正確。因為如果這一行中剛好有其他字段也包含了ck,那么就可能造成誤匹配。那么,怎么就對名字這個字段進行正則匹配呢?
輸出年齡小于20歲,并且名字中帶有ck內(nèi)容的人(就對名字的字段進行匹配)
awk -F , '$1 ~ /ck/ && $2 < 20{print}' test.txt
$1 ~ //則表示對第一列數(shù)據(jù)進行正則匹配。
BEGIN和END關(guān)鍵字
action里面的語句會對每一行過濾后的數(shù)據(jù)進行輸出,那么,如果我們想在輸出的頭部和尾部增加一些內(nèi)容,應(yīng)該怎么做呢?答案就是使用BEGIN和END關(guān)鍵字。記得一定要大寫
BEGIN后面跟一個語句塊{},表示在awk掃描文本前輸出一些內(nèi)容。END用法也一樣,在awk掃描文本后輸出一些內(nèi)容。
awk -F , 'BEGIN {print "name,age"} {print} END {print "end"}' test.txt
//輸出
name,age
jack,18
nick,24
joe,19
hack,19
end
上面的語句我們可以看到有3個{}語句塊,分別表示掃描前語句塊,掃描文本時使用的語句塊,掃描后語句塊。
內(nèi)置變量
ARGC 命令行參數(shù)個數(shù)
ARGV 命令行參數(shù)排列
ENVIRON 支持隊列中系統(tǒng)環(huán)境變量的使用
FILENAME awk瀏覽的文件名
FNR 瀏覽文件的記錄數(shù),也就是記錄所在的行數(shù)
FS 設(shè)置輸入域分隔符,等價于命令行 -F選項
NF 瀏覽記錄的域的個數(shù)
NR 已讀的記錄數(shù)
OFS 輸出域分隔符
ORS 輸出記錄分隔符
RS 控制記錄分隔符
awk內(nèi)置了一些變量,我們可以在語句塊直接使用 。
直接輸出第2行的數(shù)據(jù)
awk -F , 'FNR==2 {print}' test.txt
print和printf的區(qū)別
awk中同時提供了print和printf兩種打印輸出的函數(shù)。
其中print函數(shù)的參數(shù)可以是變量、數(shù)值或者字符串。字符串必須用雙引號引用括起來,參數(shù)必須用逗號分隔,不然多個參數(shù)之間連在一起會造成混淆。
printf和c語言中的printf基本一樣,可以格式化字符串。
print輸出例子
awk -F , '{print "name="$1",""age="$2}' test.txt
printf輸出例子
awk -F , '{printf "name=%s,age=%0.2f\n",$1,$2}' test.txt
//輸出
name=jack,age=18.00
name=nick,age=24.00
name=joe,age=19.00
name=hack,age=19.00
通過printf,我們可以將年齡轉(zhuǎn)化成小數(shù)點
三、awk 腳本
通過 -f scriptfile 來將awk執(zhí)行語句放到腳本中。我們可以編寫一個awk腳本test.awk。
BEGIN {print "name,age"}
$2 < 20 && /ck/ {print $1}
END {print "end"}
之后執(zhí)行
awk -F , -f test.awk test.txt
等同于執(zhí)行
awk -F , 'BEGIN {print "name,age"} $2 < 20 && /ck/ {print $1} END {print "end"}'
awk腳本也可以這么寫
#!/usr/bin/awk -f
BEGIN {print "name,age"}
$2 < 20 && /ck/ {print $1}
END {print "end"}
之后直接執(zhí)行該腳本即可
./test.awk -F , test.txt
四、awk 編程
定義變量
awk語句中可以直接定義變量然后使用
# 設(shè)置count變量,統(tǒng)計一共有多少行
awk -F , '{count++;print $0} END {print count}' test.txt
# 設(shè)置count變量的初始值為1
awk -F , 'BEGIN{count=1} {count++;print $0} END {print count}' test.txt
我們可以在BEGIN語句塊中設(shè)置變量的初始值,如果print要輸出一個沒有定義過的變量,awk也不會報錯,而是輸出空字符串。
條件語句
awk的條件語句也和C語言基本一樣。
# 如果歲數(shù)小于20歲并且名字字段帶有ck,輸出的歲數(shù)就+5,否則就+1
awk -F , '{if($2<20 && $1 ~ /ck/){print $1,$2+5}else{print $1,$2+1}}' test.txt
上面的語句就是我們常見的if…else,很好理解。
循環(huán)語句
awk的循環(huán)語句也和C語言基本一樣。支持while、do/while、for、break、continue這些關(guān)鍵字。
# 每一行重復(fù)輸出3次
awk -F, 'BEGIN{i=0} {while(i<3){print $0;i++};i=0}' test.txt
awk -F, '{for(i=0;i<3;i++){print $0}}' test.txt
數(shù)組
awk的數(shù)組的下標可以是數(shù)字或者字母,這和js的map比較像。
# 輸出的過程中,遇到名字是nick的,把它的名字轉(zhuǎn)換成 hello 。最后我們再輸出一個world
awk -F, 'BEGIN{nickname["nick"]="hello";nickname[1]="world"} {if(nickname[$1]!=""){print nickname[$1],$2}else{print $1,$2}} END{print nickname[1]}' test.txt
上面的語句在BEGIN塊中定義了nickname的數(shù)組,同時使用了兩種下標,分別是"nick"和數(shù)字1。之后在后面也用到了。
五、寫在結(jié)尾
awk是linux上一款處理文本的神器,以前看到或者要用的時候總是習慣去百度,然后直接抄過來改一點東西,而沒有去較系統(tǒng)的學習一下。主要還是被它那看似復(fù)雜的語句塊嚇住,今天在認真看了幾篇awk教程后發(fā)現(xiàn)其本質(zhì)也很簡單,學習起來其實很快。個人覺的有編程基礎(chǔ)的人,差不多半個小時就足以將awk掌握個大概。
當然,要深入的學習awk肯定不是一件簡單的事,本篇博客也只是對awk的語句進行一些簡單的介紹,也足以應(yīng)付我們工作中大部分的需求。如果想深入學習awk的同學可以去官方文檔http://www.gnu.org/software/gawk/manual/gawk.html學習看看。