Linux之强大的gawk
awk介紹
awk是Linux文本處理工具三劍客之一,它是一種報表生成器,用于對文件內(nèi)容進(jìn)行各種"排版",然后進(jìn)行格式化顯示。
在Linux上,我們使用的是GNU awk 簡稱gawk,其實,gawk就是awk的鏈接文件,因此,在系統(tǒng)上使用awk和gawk是一樣的
gawk是一種過程式編程語言,它支持條件判斷,數(shù)組,循環(huán)等各種編程語言中所有可以使用的功能,因此,我們還可以把gawk稱為一種腳本語言解釋器
awk是模式掃描和處理語言,該程序通常由:?BEGIN語句塊、能夠使用模式匹配的通用語句塊 、END語句塊,共3部分組成?
awk的三種運行方式:
(1) awk 命令行
awk(2) awk 程序文件
awk -f /path/from/awk_script(3) awk 腳本
#!/bin/awk -fawk 的基本用法
awk [options] 'program' var=value file ...awk [options] -f programfile var=value file ...awk [options] 'BEGIN{ action;...} pattern{ action;...} END{ action;... }' file ...?awk [options] 'program' FILE1 FILE2 ...
????program : PATTERN {ACTION STATEMENT}
????????program : 編程語言,通常是被單引號或雙引號引中
????????PATTERN : 模式,決定動作語句何時觸發(fā)及觸發(fā)事件 (BEGIN,END)
????????ACTION STATEMENT :動作語句,可以是由多個語句組成,各語句之間使用分號分割,,放在{}內(nèi)指明 (print, printf)
????options :?
????????-F :指明輸入字段的分隔符,默認(rèn)為空白字符
????????-v var=value : 自定義變量
分隔符,域和記錄:
????awk執(zhí)行時,由分隔符分割的字段(域)標(biāo)記 $1,$2,...$n 稱為域標(biāo)識。$0表示所有域,注意,和shell變量中的$符號含義不同
????文件的每一行稱為記錄
????省略action,則默認(rèn)執(zhí)行 print $0 的操作
awk工作原理
第一步 : 執(zhí)行BEGIN{ACTION;...}語句塊中的語句
第二步 : 從文件或標(biāo)準(zhǔn)輸入(stdin)讀取一行,然后執(zhí)行 pattern{action;...}語句塊,它逐行掃描文件,從第一行到最后一行重復(fù)這個過程,直到文件全部被讀取完畢
第三步 : 當(dāng)讀取至輸入流末尾時,執(zhí)行END{ACTION;...}語句塊
BEGIN 語句塊在awk開始從輸入流中讀取之前被執(zhí)行,這是一個可選的語句塊,比如變量初始化,打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中
END 語句塊在awk從輸入流中讀取完所有的行之后即被執(zhí)行,比如打印所有行的分析結(jié)果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊
pattren 語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認(rèn)執(zhí)行{print},既打印每一個讀取到的行,awk讀取的每一行都會執(zhí)行該語句塊
awk命令
1, print
用法: print item1,item2,...
????item : 字符串,用引號引用
????變量 : 顯示變量的值,可以直接使用變量的名進(jìn)行引用
????數(shù)值 : 無須加引號
要點:?
????(1) : 逗號分隔符
????(2) : 輸出的各item可以是字符串,也可以是數(shù)值,當(dāng)前記錄的字段,變量或awk的表達(dá)式
????(3) : print后面的item省略時,相當(dāng)于運行 print $0 ,用于輸出整行
示例:
awk?'{print?"hello?awk"}'?/etc/fstab awk?-F:?'{print?$1,$3}'?/etc/passwd awk?-F:?'{print?$1"\t"$3}'?/etc/passwd????
2, 變量?
????變量分為內(nèi)建變量和自定義變量
2.1 內(nèi)建變量
????FS : 輸入字段分隔符,默認(rèn)為空白字符
awk -v FS=":" '{print $1,$3}' /etc/passwd awk -F: '{print $1,$3}' /etc/passwd????OFS : 輸出字段分隔符,默認(rèn)為空白字符
awk -v FS=":" -v OFS="---" '{print $1,$3}' /etc/passwd????RS : 輸入記錄分隔符,指定輸入時的換行符,原換行符仍有效
awk -v RS=':' '{print}' /etc/passwd????ORS : 輸出記錄分隔符,輸出時用指定符號代替換行符
awk -v ORS='####' '{print}' /etc/passwd????NF : 字段的數(shù)量
awk -F: '{print NF}' /etc/passwdawk -F: '{print $(NF-1)}' /etc/passwd????NR : 行號
awk '{print NR}' /etc/fstab awk 'END{print NR}' /etc/fstab????FNR : 分別統(tǒng)計各文件的行號
awk '{print FNR}' /etc/fstab /etc/passwd????FILENAME : 當(dāng)前文件名
awk 'END{print FILENAME}' /etc/fstab????ARGC : 命令行參數(shù)的個數(shù),awk也算一個參數(shù)
awk '{print ARGC}' /etc/fstab /etc/passwd?????ARGV : 數(shù)組,保存的是命令行所給定的各參數(shù)
awk 'BEGIN{print ARGV[0]}' /etc/fstab??
2.2 自定義變量
????(1) -v var=vaule 變量名區(qū)分字符大小寫
????(2) 在program中直接定義
示例:
awk?-v?test='hello?awk'?'BEGIN{print?test}' awk?'BEGIN{test="hellp";print?test}'3, printf 命令
格式化輸出 : printf "FORMAT", item1.item2,...
????(1) 必須指定FORMAT
????(2) 不會自動換行,需要顯示給出換行控制符,\n
????(3) FORMAT 中需要分別為后面每個item指定格式符
格式符: 與 item 一一對應(yīng)?
%c : 顯示字符的ascii碼%d,%i : 顯示十進(jìn)制整數(shù)%e,%E : 科學(xué)計數(shù)法數(shù)值顯示%f : 顯示為浮點數(shù)%g,%G : 以科學(xué)計數(shù)法或浮點形式顯示數(shù)值%s : 顯示字符串%u : 無符號整形%% : 顯示%自身修飾符:
#[.#] : 第一個數(shù)字控制顯示的寬度,第二個#表示小數(shù)點后的精度 ?%3.1f ?
- : 左對齊 (默認(rèn)右對齊) ?%-15s
+ : 顯示數(shù)值的符號 ?%+d
示例:
awk?-F:?'{printf?"%-15s%d\n",$1,$3}'?/etc/passwd awk?-F:?'{printf?"ername:?%s,UID:%d\n",$1,$3}'?/etc/passwd4,awk的操作符
操作符:
算術(shù)操作符:
+;-;*;/;^;%-x :轉(zhuǎn)換正負(fù)+x :把字符串轉(zhuǎn)換為數(shù)值字符串操作符:沒有符號的操作符表示字符串連接
賦值操作符:
=,+=,-=,*=,/=,%=,^=,--,++比較操作符:
>,>=,<=,!=,==模式匹配符:
~ : 是否匹配!~ : 不能夠匹配# awk –F: '$0 ~ /root/{print $1}' ?/etc/passwd?#?awk ?'$0 ?!~ /root/' ? /etc/passwd邏輯操作符:
&&;||;!示例:
awk -F: '$3>=500{print $1,$3}' /etc/passwd????
awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd?awk -F: '!($3==0) {print $1}' /etc/passwd?awk -F: '!($3>=500) {print $3}}' /etc/passwd?函數(shù)調(diào)用: function_name(arg1,arg2,...)
條件表達(dá)式(三目表達(dá)式)
selector?if-true-expression:if-false-expression示例:
tail?-4?/etc/passwd|awk?-F:?'{$3>=500?usertype="common?users":usertype="system?users";printf?"%-15s%s\n",$1,usertype}'????
5,PATTERN 模式
pattern : 根據(jù)pattern條件,過濾匹配的行,在做處理
(1) 如果未指定,空模式,匹配文本的每一行
(2) [!]/regular expression/ : 僅處理能夠模式匹配到的行,需要用 / /括起來
awk?'/^UUID/{print?$1}'?/etc/fstab awk?'!/^UUID/{print?$1}'?/etc/fstab(3) relational expression : 關(guān)系表達(dá)式,結(jié)果有'真'有'假',結(jié)果為真時才會被處理
????真 : 結(jié)果為非0值,非空字符串
????假 : 結(jié)果為空字符串或0值
示例:
?awk??'!0'??/etc/passwd?;?awk??'!1'???/etc/passwd?awk?–F:?'$3>=1000{print?$1,$3}'??/etc/passwd?awk?-F:?'$3<1000{print?$1,$3}'??/etc/passwd?awk?-F:?'$NF=="/bin/bash"{print?$1,$NF}'?/etc/passwd?awk?-F:?'$NF~/bash$/{print?$1,$NF}'?/etc/passwd(4) line ranges : 行范圍
????
startline,endline : /part1/,/part2/ 不支持直接給出數(shù)字格式:
awk?-F:?'/^root/,/^nobody/{print}'?/etc/passwd awk?-F:?'NR>10&&NR<=15{print}'?/etc/passwd(5) BEGIN/END 模式
BEGIN{} : 僅在開始處理文件中的文本之前執(zhí)行一次END{} : 僅在文本處理完成之后執(zhí)行一次示例:
awk?-F:?'BEGIN?{print?"USER?USERID"}?{print?$1":"$3}?END{print?"end?file"}'?/etc/passwd?awk?-F:?'{print?"USER?USERID“;print?$1":"$3}?END{print?"end?file"}'?/etc/passwd?awk?-F:?'BEGIN{print?"??USER??UID??\n?--------------"}{print?$1,$3}'?/etc/passwd?seq?10?|awk?'i=0'?seq?10?|awk?'i=1'seq?10?|?awk?'i=!i'seq?10?|?awk?'{i=!i;print?i}'??seq?10?|?awk?'!(i=!i)'?seq?10?|awk?-v?i=1?'i=!i'6,常用action
(1) Expression :算術(shù),比較表達(dá)式等
(2) Control statements : if,while等
(3) Compound statements : 組合語句
(4) input statements
(5) output statements : print等
7,控制語句
if(condition){statements;...}if(condition){statements;...}else{statements;...}while(condition) {statements;...}do{statements;...} while(condition)for(expr1;expr2;expr3){statements;...}breakcontinuedelete array[index]delete arrayexit{statements;...} 組合語句7.1 if-else:
語法:?
if(condition)statement [else statement]if(condition1){statement1}else if(condition2){statement2} else{statement3}? awk?-F:?'{if($3>=500)print?$1,$3}'?/etc/passwd awk?-F:?'{if($3>=300)?{printf?"ok:%s\n",$1}?else?printf?"no:%s\n",$1}'?/etc/passwd df?-h?|?awk?-F'%'?'/^\/dev/{print?$1}'|awk?'{if($NF>4)print?$1}'使用場景:對awk取得的整行或某個字段做條件判斷
awk?-F:?'{if($3>=1000)print?$1,$3}'?/etc/passwd? awk?-F:?'{if($NF=="/bin/bash")?print?$1}'?/etc/passwd? awk?'{if(NF>5)?print?$0}'?/etc/fstab? df?-h|awk?-F%?'/^\/dev/{print?$1}'|awk?'$NF>=80{print?$1,$5}'7.2 while 循環(huán):
語法: while(condition)statement
????條件為真,進(jìn)入循環(huán),條件為假,退出循環(huán)
使用場景:對一行內(nèi)多個字段逐一類似處理時使用:對數(shù)組中的各元素逐一處理時使用
????length() 字段長度
awk?'/^[[:space:]]*linux/{i=1;while(i<=NF){print?$i,length($i);i++}}'?/etc/grub2.cfg????????#centos?7 awk?'/^[[:space:]]*linux/{i=1;while(i<=NF){if(length($i)>10)print?$i,length($i);i++}}'?/etc/grub2.cfg??#centos?77.3 do-while 循環(huán):
語法: do {statement;...} while(condition)
????意義:無論真假,至少執(zhí)行一次循環(huán)體
示例:
[root@centos6?~]#?awk?'BEGIN{sum=0;i=0;do{sum+=i;i++}while(i<=100)print?sum}' 50507.4 for 循環(huán):
語法: for(expr1;expr2;expr3) {statement;...}
awk?'/^[[:space:]]*linux/{for(i=1;i<=NF;i++){print?$i,length($i)}}'?/etc/grub2.cfg特殊用法:
????可以遍歷數(shù)組中的每一個元素
????語法: for(var in array){condition}
性能比較(awk 和 shell 中for循環(huán)所需的時間)
time?(sum=0;for?i?in?{1..10000};do?let?sum+=i;done;echo?$sum) time?(awk?'BEGIN{sum=0;i=0;do{sum+=i;i++}while(i<=10000)print?sum}') time?(sum=0;for((i=0;i<=10000;i++));do?let?sum+=i;done;echo?$sum)7.5 switch語句
語法: switch(expression){case VALUE or /REGEXP/:statement;...;default:statement}
7.6 break和continue
7.7 next
提前結(jié)束對本行的處理而直接進(jìn)入下一行
awk?-F:?'{if($3%2!=0)?next;print?$1,$3}'?/etc/passwd8,數(shù)組
關(guān)聯(lián)數(shù)組: array[index-expression]
index-expression :
(1) : 可使用任意字符串,字符串要使用雙引號括起來
(2) : 如果某數(shù)組元素事先不存在,在引用時,awk會自動創(chuàng)建此元素,并將其值初始化為"空串"
若要判斷數(shù)組中是否存在某元素,要使用"index in array"格式進(jìn)行遍歷
awk?'BEGIN{weekdays["mon"]="Monday";?weekdays["tue"]="Tuesday";print?weekdays["mon"]}'? awk?'!a[$0]++'?dupfile若要遍歷數(shù)組中的每個元素,要使用for循環(huán)
for(var in array){for-body}
注意: var 會遍歷array的每個索引
awk?'BEGIN{k["a"]="aaa";k["b"]="bbb";for(i?in?k)print?k[i]}' netstat?-tan?|?awk?'NR>2{k[$NF]++;}END{for(i?in?k)print?k[i],i}'9,函數(shù)
數(shù)值處理:
????rand();返回0和1之間一個隨機(jī)數(shù),這個產(chǎn)生的隨機(jī)數(shù)是不變的
????
????如果要產(chǎn)生隨機(jī)數(shù),需要srand() 函數(shù)
awk 'BEGIN{srand() ;print int(rand()*1000000)}' #有點問題????
字符串處理:
????length([s]) : 返回指定字符串的長度
????sub(r,s,[t]) : 對t字符串進(jìn)行搜索r表示的模式匹配的內(nèi)容,并將第一次匹配的內(nèi)容替換為s
????
? ? ?gsub(r,s,[t]) : 對t字符串進(jìn)行搜索r表示的模式匹配的內(nèi)容,并將匹配的所有內(nèi)容都替換為s
????
????split(s,array,[r]) : 以r為分隔符,切割字符s,并將切割后的結(jié)果保存到array所表示的數(shù)組中,第一個索引值為1,不是0;第二個索引值為2;...
netstat?-ant?|?awk?'/^tcp\>/{split($5,ip,":");count[ip[1]]++?}END{for(i?in?count){print?i,count[i]}}'自定義函數(shù):
函數(shù):
function name (parameter,parameter,...){statementsreturn expression}示例:
????#cat fun.awk
function max(a,b){a>b?var=a:var=breturn var}BEGIN{a=3;b=2;print max(a,b)} awk -f fun.awk ?????
awk中調(diào)用shell命令
system 命令
空格是 awk 中的字符串連接符,如果 system 中需要使用 awk 中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用""引起來
awk腳本
將awk程序?qū)懗赡_本,直接調(diào)用或執(zhí)行
比如:
??
向awk腳本參數(shù)
格式: awkfile var=value var2=value2 ... InputFile
示例:
? ?
練習(xí)
1、統(tǒng)計/etc/fstab文件中每個文件系統(tǒng)類型出現(xiàn)的次數(shù)?
2、統(tǒng)計/etc/fstab文件中每個單詞出現(xiàn)的次數(shù)
3,求每班總成績和平均成績,成績表格式如下
name class score
wang ? 1 ? ?100
zhang ?2 ? ?90
li ? ? 1 ? ?80
awk?'BEGIN{print?"班級?總成績?平均成績"}{if($2==1){sum1+=$3;count1++}else?if($2==2)?{sum2+=$3;count2++}}END{printf?"?1?%7d???%3.2f\n",sum1?,sum1/count1;printf?"?2?%7d???%3.2f\n",sum2?,sum2/count2}'?test總結(jié)
以上是生活随笔為你收集整理的Linux之强大的gawk的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Saas浅谈
- 下一篇: [免费专栏] 车联网基础理论之车联网安全