awk:報告生成器,格式化文本輸出
處理方式:文件里有多行,awk處理時,先將第一行放到內存里面,然后將該行分割成列(字段),第一個字段叫$1,第二個字段$2,以此類推,$0代表整行。
基本用法:
awk [option] 'program' var=value file…..
awk [option] -f programfile var=value file……
awk [option] 'BEGIN{action;….} parttern{action;…..}END{action;……}' file
語句之間要用“”;”分號分割
awk 程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊,共3部分組成
option:
-F :指明輸入時用到的字符分隔符(不指明系統默認空白或tab為分隔符)
-v: var=value 自定義變量
1、print item1,item2….
不同item之間要用“”,“”逗號作為分隔符,且輸出顯示時用空格隔開
如果此處省略item,則相當于print $0,文件有多少行,則打印多少個行
輸出的item可以是字符串,也可以是數值,當前記錄的字段,變量或awk的表達式
2、變量
內置變量:
FS:input field seperator 輸入字段分隔符,默認為空白符
awk -v FS=":" '{print $1,$3}' /etc/passwd 等同于 awk -F: '{print $1,$3}' /etc/passwd
OFS:output field seperator 輸出字段分隔符,默認空白符
awk -F: -v OFS="----" '{print $1,$3}' /etc/passwd xixi----3015 aa----3016 apache----48
RS:input record seperator 輸入時的換行符
ORS:output record seperator 輸出時的換行符
NF:number of field,字段數量
print NF:打印字段數量 print $NF:打印最后一個字段
awk -F: '{print NF}' /etc/passwd 7 ... 7 awk -F: '{print $NF}' /etc/passwd /bin/bash .... /sbin/nologin
NR:number of record 行號
root@centos7.2 ~ # awk -F: '{print NR,$0}' /etc/fstab /etc/issue 1 ....... 11 UUID=fca23b64-0367-45b2-ab0e-b391bbba6ec8 swap swap defaults 0 0 12 \S .......... 17 \n 18 \t
FNR:每個文件進行單獨記錄行號
root@centos7.2 ~ # awk -F: '{print FNR,$0}' /etc/fstab /etc/issue 1 ...... 10 UUID=068d63ab-d4b7-4e1f-b00b-c182785fa85d /boot xfs defaults 0 0 11 UUID=fca23b64-0367-45b2-ab0e-b391bbba6ec8 swap swap defaults 0 0 1 \S ...... 6 \n 7 \t
FILENAME:顯示文件名
root@centos7.2 ~ # awk '{print FILENAME,$0}' /etc/issue /etc/issue \S ........ /etc/issue \n /etc/issue \t
ARGC:命令行參數的個數
root@centos7.2 ~ # awk '{print ARGC}' /etc/issue 2 2 2
ARGV:數組,保存命令行中的各個參數,ARGV[0]
root@centos7.2 ~ # awk '{print ARGV[0]}' /etc/issue awk 。。。。 awk
自定義變量:
a、-v var=value 注意變量名區分大小寫
root@centos7.2 ~ # awk -v a="superman" 'BEGIN{print a}{print a,$0}' /etc/issue superman superman \S superman Kernel \r on an \m ........ superman \t
b、在program直接定義
root@centos7.2 ~ # awk 'BEGIN{a="superman";print a}' superman
3、printf命令:
格式化輸出:printf format,item1,item2…….
注意:format必須要給出
不會自動換行,需要給出換行符"\n"
format 中需要分別為后面的每個item指定一個格式化符號;
格式符:
%c:顯示字符的ASCII碼
%d:顯示十進制整數
%f:顯示為浮點數
%e,%E:科學計數法數值顯示
%g,%G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%:顯示% 自身
修飾符:
#[.#]:第一個#數字用來控制顯示的寬度,第二個#表示小數點后的精度
%3.1:右對齊 %-3.1:左對齊 %+3.1:顯示數值的符號
root@centos7.2 ~ # awk -F: '{printf "UserName:%-16s,Uid:%10d\n",$1,$3}' /etc/passwd UserName:root ,Uid: 0 UserName:bin ,Uid: 1 UserName:daemon ,Uid: 2 UserName:adm ,Uid: 3
4、操作符
算數操作符: x+y,x-y,x*y,x/y,x^y,-x,+x:轉換為數值
root@centos7.2 ~ # awk 'BEGIN{print 4*5}' 20
字符串操作符:沒有符號的操作符
賦值操作符: =,+=,-=,*=,/=,%=,^= ,++,–
awk 'BEGIN{i+=5;print i}'
比較操作符:>,>=,<,<=,!=,==
模式匹配符:
~:是否匹配
!~:左側的字符串是否不能夠被右側的字符串匹配
root@centos7.2 ~ # awk -F: '$0~/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin root@centos7.2 ~ # awk -F: '$0~/^root/' /etc/passwd root:x:0:0:root:/root:/bin/bash root@centos7.2 ~ # awk -F: '$0~"root"' /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin root@centos7.2 ~ # root@centos7.2 ~ # awk -F: '$1=="root"' /etc/passwd root:x:0:0:root:/root:/bin/bash
邏輯操作符:&&,||,!
root@centos7.2 ~ # awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd root bin ....... root@centos7.2 ~ # awk -F: '$3 ==0 || $3>=1000 {print $1}' /etc/passwd root nfsnobody ..... root@centos7.2 ~ # awk -F: '!($3>=500) {print $3}' /etc/passwd 0 1 2
函數調用:function_name(argu1,argu2,。。。)
條件表達式:
selector?if-true-experssion:if-false-expression 注意第二個if前面是“”:“”冒號
如果UID大于1000就顯示為普通用戶,否則顯示為系統用戶,并打印出用戶名和uid awk -F: '{$3>=1000?user="common user":user="system user";print user":"$1":"$3}' /etc/passwd
5、Pattern
1)empty:處理文本的每一行
2)/regular expression/:僅能夠處理被此模式匹配到的行
root@centos7.2 ~ # awk '/^UUID/{print $1}' /etc/fstab UUID=5f2cc971-2611-46f5-a14c-9e730cd33aa0 UUID=068d63ab-d4b7-4e1f-b00b-c182785fa85d UUID=fca23b64-0367-45b2-ab0e-b391bbba6ec8
3)relational expression:關系表達式:結果有真有假,如果為真才會處理,真表示結果為非0值,非空位真
awk -F: '$3>=1000{print $3}' /etc/passwd awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd ###if判斷要放到{}里面 awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd
4)relational expression: 關系表達式;結果有“真”有“假”;結果為“真”才會被處理;
真:結果為非0值,非空字符串
假:結果為空字符串
awk 'j=1{print $0};i=0{print i,j}' /etc/passwd ###j=1的print動作會執行 awk ‘!arr[$0]++’file 去除文件中的重復行 root@centos7.2 ~ # seq 10 | awk 'i=!i' ###打印基數行 awk ?。╥=!i) 打印偶數行 1 3 5 7 9
4)地址定界:行范圍
startline,endline:/part1/,/part2/
awk -F: '/^root/,/^naruto/{print $1,$NF}' /etc/passwd 注意不支持直接給出數字的格式 awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd 打印2-10行 ### 不帶if的在{}外面判斷 上述表達式等同于awk -F: '{if(NR>=2&&NR<=10)print $1}' /etc/passwd
5)BEGIN/END模式
BEGIN{}:僅在開始處理文件之前執行一次的程序
END{}:僅在文件處理之后執行一次
awk -F: 'BEGIN{print " username uid \n--"}{printf "%-10s %s\n",$1,$3}END{print "---\nend"}' /etc/passwd
6、常用的action
1)experssions 表達式
2)Control statements,if,while等
3) compund statements:組合語句;
4)input statements
5)output statement 輸出語句
7、控制語句
if(condition){statements}
if (condition){statements} else {statements}
while (condition){statments}
do {statements} while(condition)
for (expr1;expr2;expr3){statements}
break
continue
delete array [index]
delete array
exit
7.1 if-else
語法:if (condition)statement [else statement]
使用的場景:對awk取得的整行或某個字段做條件判斷
awk -F: '{if(NR>=2&&NR<=10)print $1}' /etc/passwd ###if判斷在{}里面 awk -F: '{if($3>=1000) {printf "ComUser:%s\n",$1} else {printf "rootUser: %s\n",$1}}' /etc/passw awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd awk -F: '{if(NF>5)print $0}' /etc/passwd df | awk -F"%" '/^\/dev/{print $1}' | tr -d %|awk '{if($NF>=20)print $1}'
注意:如有else 其兩邊都要加{}
7.2 while循環
語法:while(condition) statement,條件真進入循環,條件假退出
使用場景:對一行內的多個字段逐一類似處理時使用,對數組中的各個元素逐一處理時使用
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7)print $i,length($i);i++}}' /etc/grub2.cfg
7.3 do-while循環
語法:do statement while(condition)
意義:至少執行一次循環體
7.4 for循環
語法:for(expr1;expr2;expr3)statement
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
7.5 switch語法
語法:switch(expression) {case Value1 or /regexp/:statement;case\ value2 or /regexp2/:statement;….default:statement}
7.6 break和continue 用法同bash
break [n]
root@centos7.2 ~ # awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==11){break}sum+=i}print sum}' 55
continue
root@centos7.2 ~ # awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue}sum+=i}print sum}' 2500
7.7 next 能提前結束本行的處理,進入下一行
awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd
7.8 性能比較 time(command)
root@centos7.2 ~ # time (awk 'BEGIN{sum=0;for(i=1;i<=100000;i++){sum+=i};print sum}') 5000050000 real 0m0.046s user 0m0.032s sys 0m0.014s root@centos7.2 ~ # time (sum=0;for((i=1;i<=100000;i++));do let sum=$[sum+i];done;echo $sum) 5000050000 real 0m1.085s user 0m1.042s sys 0m0.044s
root@centos7.2 ~ # awk 'BEGIN{sum=0;for(i=1;i<=10000;i++){sum+=i}}{print }END{print sum}' ##沒有任何輸出結果,等待輸入,因為沒有文本傳入,且END是等待處理問文本之后才輸出,所以在此處處于等待狀態 root@centos7.2 ~ # awk 'BEGIN{sum=0;for(i=1;i<=10000;i++){sum+=i}}{print }END{print sum}' /etc/passwd root:x:0:0:root:/root:/bin/bash ....... apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin 50005000
8、array數組
關聯數組:array[index-expression]
1)可以使用任意字符串;字符串要加雙引號
2)如果某數組元素事先不存在,在引用時,awk自動創建此元素,并將其值初始化為“空串”
root@centos7.2 ~ # awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";print weekdays["tue"]}' tuesday
要遍歷數組中的每個元素,要使用for循環,注意:var會遍歷array的每個索引
for(var in array )
root@centos7.2 ~ # awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";for(i in weekdays)print weekdays[i]}' tuesday monday
root@centos7.2 ~ # netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}' LISTEN 4 ESTABLISHED
root@centos7.2 ~ # awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log 192.168.1.101 56 192.168.1.103 14 ::1 10
統計/etc/fstab文件中每個文件系統類型出現的次數 awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab
統計指定文件中每個單詞出現的次數 awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab
9、函數
內置函數
數值處理:
rand():返回0和1 之間一個隨機數,小數
awk 'BEGIN{print rand()}' ### 第一次取隨機的,之后再取,同上次一樣 awk 'BEGIN{srand();print rand()}' ###如需每次取值都不一樣需要調用srand()函數
字符串處理:
length([s]):返回指定字符串的長度
sub(r,s,[t]):以r表示的模式查找t所表示的字符串中的匹配的內容,并將其第一次出現替換為s所表示的內容
root@centos7.2 ~ # echo "2008:08:08 08:08:08" | awk 'sub(/:/,"",$1)' 200808:08 08:08:08 awk -F: '{print sub(o,O,$1)}' /etc/passwd
gsub:表示全局替換
split(s,a[,r]):以r為分隔符切割字符,并將切割后的結果保存在a所表示的數組中;
netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]++]}END{for(i in count) {print i,count[i]}}'
自定義函數
格式:
function name(parameter,parameter,……){
statements
return expression
}
示例:
#cat fun.awk function max(v1,v2) { v1>v2?var=v1:var=v2 return var } END{a=3;b=2;print max(a,b) root@centos7.2 ~ # awk -f fun.awk 3
#!/bin/awk -f # 內容要寫awk的語法,-f指定要讀取文件內容 function max(v1,v2) { v1>v2?var=v1:var=v2 return var } BEGIN{a=3;b=2;print max(a,b);} root@centos7.2 ~ # ./fun.awk 3
#!/bin/awk -f # 內容要寫awk的語法,-f指定要讀取文件內容 function max(v1,v2) { v1>v2?var=v1:var=v2 return var } BEGIN{print max(a,b);} root@centos7.2 ~ # ./fun.awk -v a=100 -v b=200 200
awk中調用shell命令:
system命令:
空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用""引用起來。
awk 'BEGIN{system("hostname") }' awk 'BEGIN{a=12; system("echo " a) }'
原創文章,作者:Naruto,如若轉載,請注明出處:http://www.www58058.com/47628
awk是一個很方便的文本格式化工具,這也是以后面試題必會遇到的面試題,希望下來多加練習,熟練掌握.