Awk介紹
?
報告生成器,格式化文本輸出
gawk:模式掃描和處理語言
基本用法:
Awk [option] ?‘program’?var=value file
Awk [ option] ?-F ???programfile var =value file ??F指明分隔符
Awk [option ] ??‘BEGIN’{ACTION…} ?pattern{action;…} ??END{action;,,,}’???file,,,
Begin,沒開始讀,就開始做什么事,做表頭
End,讀完所有的行,干的事,統計平均成績
工作原理:一行一行處理,自動讀下一行,按定義的分隔符切割成字段,字段名,$1,$2,$3,,,對字段,輪流處理
基本格式
Awk ?[option] ???‘program’?????file
選項 ???awk自己的程序 ??要處理的文件
Program: ??pattern{action statements;….} ??滿足pattern就執行action,不滿足就跳到下一行
模式 ???動作指令
Pattern部分決定動作語句合適觸發及觸發事件
Begin ???end
Action statements 對數據進行處理,放在{}內指明
Print打印必要的數據 ?printf詳細的定義顯示的格式,空格數,小數位
分隔符、域和記錄
Awk執行時,由分隔符分隔的字段(域)標記$1,$2,,,,$n 稱為域標識、$0為所有域,
文件的每一行稱為記錄,
省略action,則默認執行 print $0 的操作
?
Awk的工作原理
第一步:執行begin{action}語句塊中的語句
第二步:從文件或標準輸入(stdin)讀取一行,然后執行pattern
{action,,}語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢
第三步:當讀至輸入流末尾時,執行END{action}語句塊
Begin語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通??梢詫懺赽egin語句塊中
End語句塊在awk從輸入流中讀取完所有的行之后即被執行,比如打印所有行的分析結果這類信息匯總都是在end語句塊中完成,它也是一個可選語句塊
Pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{print}即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊
Print格式:print item1,item2,,,,
要點:1逗號分隔符
2輸出的各item可以是字符串,也可以是數值;當前記錄的字段、變量或awk的表達式
3如省略item ??相當于print$0
實例: awk -F: ‘{print $3}’ /etc/passwd ???以:為分隔符 取第三列
df |grep /dev/sd |awk ‘{print $5}’ 以默認空白為分隔符,取第五列
Field,域,字段,列,column,屬性
行,記錄,record
Awk:內置和自定義變量
?
?
FS:輸入字符分隔符,默認為空白字符
FS內置變量,使用時要寫-v
Awk -v FS=’:’??‘{print $1,FS,$3}’?/etc/passwd
Awk -F: ??‘{print $1,$3,$7}’?/etc/passwd
OFS:輸出字段分隔符,默認為空白字符
輸出的時候,定義為+為分隔符,OFS需要寫-v,顯示
Awk -v FS=’:’?-v OFS ’:’?‘{print $1,$3,$7}’?/etc/passwd
RS:輸入記錄分隔符,指定輸入時的換行符
輸入記錄換行符,默認為回車,
右圖自定義為;碰見一個;就為一行
ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
定義—-為輸出記錄分隔符,即輸出時—分隔一行
NF:字段數量?(NF本身就是一個變量,表示字段的數量) $NF 最后一個字段?$(NF-1)倒著數第一列
Ss -nt ?ss命令用來顯示處于活動狀態的套接字信息
df命令參數功能:檢查文件系統的磁盤空間占用情況
$(NF-1) 倒數第二個字段
Httpd的訪問日志,取$1
NR:記錄號
Awk ?‘{print NR}’??/etc/fstab
FNR:各文件分別計數,記錄號
FILENAME:當前文件名
打印行號,空格也算一行,
FNR, 各文件獨立編號 ??FILENAME:當前文件名
加文件名,各文件獨立顯示
ARGC:命令行參數的個數
ARGV: 數組,保存的是命令行所給定的各參數
命令行三個參數,’{}’是awk的程序
?
?
自定義變量(區分字符大小寫)
可以在外面定義,也可以在里面定義
- -v var =value
- 在program中直接定義
-f ?可以調用腳本
格式化輸出Printf命令: ?“FORMAT”, item1,item2,,,
- 必須指定FORMAT
- 不會自動換行,需要顯示給出換行控制符,\n
- FORMAT中需要分別為后面每個item指定格式符
格式符:與item一一對應
%c:顯示字符的ASCII碼
%d:%i:顯示十進制整數
%e:%E:顯示科學計數法數值
%顯示為浮點數
%g,%G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%:顯示%自身
修飾符:#[.#]:第一個數字控制顯示的寬度;第二個#表示小數點后精度,%3.1f
– :左對齊(默認右對齊) %-15s
+ :顯示數值的正負符號%+d
“”雙引號里面的表示格式,%S $1按照字符串格式顯示出來,默認不換行
%d $3 按照數字的格式顯示出來 ?????????????\n 表示換行
%-30s ?表示的是字符左對齊,控制顯示30字符,
%6d ??表示的是數字右對齊,控制數字顯示6字符
BEGIN在執行之前, 只是執行一次, 小數后面的位數溢出,自動四舍五入
例:
當讀入一行,由于pattern沒有定義,所以這個行就符合條件,符合條件,就執行action,就是打印,即print,hello.awk 執行結果和etc/fstab無關,只是這個文件有幾行,就打印幾次hello.awk
可以管道,cat /etc/fstab | awk ‘{print “hello,awk”}’
可以重定向,awk ??’{print “hello,awk”}’??< /etc/fstab
支持/n換行 ??awk ‘{print “hello,awk\nhello.27class”}’ /etc/fstab
支持運算 ????awk ‘{print 2*3}’ /etc/fstab
可以用cut -d: -f3 /etc/passwd
awk -F: ‘{print $1,$3,$7}’ /app/passwd ?-F:分隔符為:沒有寫pattern,就是每一條都符合,按:來取,$3,就是取第三行uid,
Awk 默認的分隔符為 空白符
取分區利用率,$5第五行 ,
$1 $5 之間用逗號隔開,輸出為空格,也可以在括號內用“ ”使用空格,$1時變量不能使用“”,“”表示使用的是字符串 ?“\t”“\n”也可以
$0表示打印整行,什么也不寫默認打印$0
操作符
算數操作符
X+y,x-y,x*y, x/y,x^y, ??x%y
-x:轉換為負數
+y:轉換為正數
字符操作符:沒有符號的操作符,字符串連接
賦值操作符:
=,+=,-=,*=,/=,%=,^=,
++,–
[root@Centos6 ~]# awk ‘BEGIN{i=0;print ++i,i}’ 先做運算,在打印出來
1 1
[root@Centos6 ~]# awk ‘BEGIN{i=0;print i++,i}’先賦值,在進行加運算
0 1
比較操作符
==, ?!= ?>, ?>=, ??< ???<=
模式匹配符:
~:左邊是否和右邊匹配包含 ?!~:是否不匹配
實例
[root@Centos6 ~]# awk ‘$0 ~ “^wang”‘ /etc/passwd
wang:x:500:500::/home/wang:/bin/bash
[root@Centos6 ~]# awk ‘$0 ~ “^root”‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
表示以wang開頭的,^表示行首,,,省略{print}表示打印全行
?[root@Centos6 ~]# awk ‘$0 ~ /^root/’ /etc/passwd
root:x:0:0:root:/root:/bin/bash
“”?/ / ?都可以表示中間的是正則表達式,效果一樣
[root@Centos6 ~]# awk ‘$0 ~ /^(root|wang)/’ /etc/passwd
root:x:0:0:root:/root:/bin/bash
wang:x:500:500::/home/wang:/bin/bash
支持擴展的正則表達式,使用””是一樣可以使用擴展正則表達式
[root@Centos6 ~]# awk -F: ‘$3==0’ /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@Centos6 ~]# awk -F: ‘$3>=1000’ /etc/passwd
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
模式匹配,相當于”$3==0{print$0}”
變量的值,0,空字符,沒定義,都當假 (在awk中0表示假,1表示真)
只要是有值,都認為為真
awk ?-v ?i=0 ?‘i’ ?/etc/issue ???相當于awk -v i=0 ‘i{print $0}’
awk ?-v ?i=”?“??‘i’ ?/etc/issue
awk ?-v ?i=””?‘i’ ?/etc/issue
邏輯操作符:與&&,或||,非!
示例
[root@Centos6 ~]# awk -F: ‘ $3 >=0 && $3<=1000 {print $1}’ /etc/passwd
[root@Centos6 ~]# awk -F: ‘ $NF ==”/bin/bash” {print $1,$NF}’ /etc/passwd
root /bin/bash
wang /bin/bash
haha /bin/bash
hehe /bin/bash
[root@Centos6 ~]# awk -F: ‘!($3==0){print $1}’ /etc/passwd
匹配不是root的其他賬號
!i++ ?先做取反,在賦值計算,++i 先賦值計算,在取反
條件表達式(三目表達式)
—?—:—
awk -F: ‘{$3>=1000?usertype=”common user”:usertype=”sysuser”;printf “%-30s:%-30s %15d ?\n”,usertype,$1,$3″}’ /etc/passwd
PATTERN:根據pattern條件,過濾匹配的行,在做處理
- 如果未指定:空模式,匹配每一行
- /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
- Relational expression:關系表達式,結果為真,才會被處理
- 真:結果為非0值,非空字符串
假:結果為空字符串或0值
[root@Centos6 ~]# awk -F: ‘/^[^#]/{print $1}’ /etc/profile
[root@Centos6 ~]grep ?‘^[^#]’???/etc/profile
awk -F: ‘!/^UUID/{print $1}’ /etc/fstab
awk -F: ‘/^UUID/{print $1}’ /etc/fstab
顯示,非#開頭的行
Seq 10
Seq 10 |sed -n ?‘1-2p’??打印奇數行
Seq 10 |sed -n ?‘2-2p’??打印偶數行
[root@Centos6 ~]# seq 10 |awk ‘!(i=!i)’
2
4
6
8
10
[root@Centos6 ~]# seq 10 |awk -v i=2 ‘(i=!i)’ 開始i=2,!i=0,不打印,第二次,i=0;!i=1,打印該行
2
4
6
8
10
[root@Centos6 ~]# seq 10 |awk ‘i=!i’ ?開始i為空,!i=1,則打印改行,第二次,i=1;!i=0,則不打印該行
1
3
5
7
9
- line ranges 行范圍
Startline,endline:/part1/,/part2/不支持直接給出數字格式
?
?
?
打印第二行到第五行
?
?
BEGIN和END模式
BEGIN{}:僅在開始處理文件中的文本之前執行一次
END{}:僅在文本處理完成之后執行一次
常用的action分類
1,算數,比較表達式
2,if,while 語句
3,組合語句
4,input statements
5,output statements:print等
Awk控制語句
{statements;…}組合語句
If(condition){statements,…}
If(condition){station;…}else{stations;…}
While(conditon){stations;…}
Do{stations;…}while(condition)
For(expr1;expr2;expr3){stations;…}
Break
Continue
Delete array[index]
Delete array
Exit
[root@Centos6 ~]# df |awk ‘{if($0 ~ /\/dev\/sd/)print $1,$5}’
/dev/sda3 8%
/dev/sda2 1%
/dev/sda1 4%
[root@Centos6 ~]# df |awk ‘/^\/dev\/sd/{print $1,$5}’
/dev/sda3 8%
/dev/sda2 1%
/dev/sda1 4%
如果分區的利用率大于80,就把分區的名稱顯示出來
[root@Centos6 ~]# df | awk -F% ‘/^\/dev\/sd/{print $(NF-1)}’
/dev/sda3 ??????50264772 3582396 ?44122376 ??8
/dev/sda2 ??????60344404 ??57644 ?57214760 ??1
/dev/sda1 ????????999320 ??34952 ???911940 ??4
[root@Centos6 ~]# df | awk -F% ‘/^\/dev\/sd/{print $(NF-1)}’|awk ‘{if($5>4)print $1,$5}’
/dev/sda3 8
[root@Centos6 ~]# df | awk -F “[ %]+” ‘/^\/dev\/sd/{if($(NF-2)>4)print $1,$5}’
/dev/sda3 8
/dev/sda2 1
/dev/sda1 4
[root@Centos6 ~]# df | awk -F “[ %]*” ‘/^\/dev\/sd/{if($(NF-2)>4)print $1,$5}’
/dev/sda3 8
/dev/sda2 1
/dev/sda1 4
表示以空格和%同時為分隔符
?
[root@Centos6 ~]# awk -F: ‘{print $1,length($1)}’ /etc/passwd
root 4
bin 3
daemon 6
統計字符串的長度
[root@Centos6 ~]# awk -F: ‘/^root/{i=1;while(i<=NF){print $i,length($i);i++}}’ /etc/passwd
root 4
x 1
0 1
0 1
root 4
/root 5
/bin/bash 9
統計root行,各字符串的長度
[root@Centos6 ~]# awk -F: ‘BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++}print sum}’
5050
[root@Centos6 ~]# awk -F: ‘BEGIN{i=1;sum=0;do{sum+=i;i++}while(i<=100);print sum}’
5050
[root@Centos6 ~]# seq -s+ 1 100
1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100
[root@Centos6 ~]# seq -s+ 1 100|bc
5050
?
While循環
語法:while(condition){statements;…}
條件“真”,進入循環;條件“假”,退出循環
使用場景:
對一行內的多個字段逐一類處理時使用
對數組中的各元素逐一處理時使用
示例
Do-while循環
語法:do{statement;…}while(condition)
意義:無論真假,至少執行一次循環體
For循環
語法:for(expr1;expr2;expr3){statements;….}
常見用法
特殊用法:能夠遍歷數組中的元素
語法for(var in array){for-body}
性能比較
time for((sum=0,i=1;i<=100;i++));do let sum+=i;done;echo $sum
[root@Centos6 ~]# time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
[root@Centos6 ~]# time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
[root@Centos6 ~]# time(sep -s “+” 10000|bc)
?
?
Switch語句
語法:switch(expression){case VALUE1 or /regexp/:statement1;case VALUE2 or /regexp2/:statement2;…default:statement}
?
Break和continue
[root@Centos6 ~]# awk -F: ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2!=0)continue;sum+=i}print sum}’
2550
[root@Centos6 ~]# awk -F: ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==10)break;sum+=i}print sum}’
45
?
Next:
提前結束對本行處理而直接進入下一行處理(awk自身循環)
[root@Centos6 ~]# awk -F: ‘{if($3%2!=0)next; print $1,$3}’ /etc/passwd
root 0
daemon 2
lp 4
只執行偶數行的循環,滿足條件即不是偶數行next,跳過 不執行
Awk數組
關聯數組:array[index-expression]
Index-expression
1,可使用任意字符串;字符串要是用雙括號括起來
2,如果某數組元素實現不存在,在引用時,awk會自動創建此元素,并將其值初始化為“空串”
若要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷
示例
f1 aa bbb ccc aaaa bbbb ccc aa bbb
awk ‘!arr[$0]++’?f1
開始aa讀進來,[“aa”]沒有定義 ?arr[“aa”]沒有值,!arr[$0]就為真,執行print;經過這次之后進行++,arr[aa]=1
同樣的道理,arr[“bbb”]沒有賦值,取反之后,!arr[“bbb”]為真,進行打印,打印之后進行++,arr[bbb]=1
………第二次遇到ccc,就不打印了,,,執行結果就是去掉重復行
Sort f1|uniq ??sort先排序,排序后
加加和賦值沒有關系,先賦值,在進行加加
第一行讀進來,沒有定義,
Arr[aa]為空,取反!arr[aa]的結果為1,
再進行加加,加加之后,數組arr[“aa”]=1
第二次,碰到aa,arr[“aa”]=1,!arr[“aa”]=0
再進行加加,數組arr[“aa”]=2
Awk ‘arr[$0]++;’?dupfile
把一個文件中的多余行去掉
Awk數組
若要遍歷數組中的每一個元素,要使用for循環
For(var in array){for-body}
注意:var會遍歷array中的每一個索引
Netstat -nat 顯示網路連接狀態
[root@centos7 ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address ??????????Foreign Address ????????State
tcp ???????0 ?????0 0.0.0.0:111 ????????????0.0.0.0:* ??????????????LISTEN
tcp ???????0 ????52 192.168.27.8:22 ????????192.168.27.1:51066 ?????ESTABLISHED
tcp6 ??????0 ?????0 :::111 ?????????????????:::* ???????????????????LISTEN
[root@centos7 ~]# netstat -tan |awk ‘/^tcp/{state[$NF]++ }END{for(i in state){print i,state[i]}}’
LISTEN 9
ESTABLISHED 1
一行一行處理,
過濾以tcp開頭的,數組的下標為$NF,最后一個變量的值當成下標,每讀出來一個值,就加一次
統計完之后,用end,for循環,把狀態遍歷出來
前面一個{}把各狀態次數,相加起來,統計的結果就是放在state[]當中
處理日志
統計每個ip訪問了多少次
當訪問次數超過1000次放到防火墻中
–j<目標>:指定要跳轉的目標;
A:向規則鏈中添加條目;
-s:指定要匹配的數據包源ip地址;
INPUT鏈:處理輸入數據包
并發連接數(正在連接的數目)達到一個數,就把他放到防火墻里,
[root@centos7 ~]# ss -nt|awk -F “[ :]+” ‘/ESTAB/{print $(NF-2)}’|sort |uniq -c
1 192.168.27.1
[root@centos7 ~]# ss -nt|awk -F “[ :]+” ‘/ESTAB/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}’
192.168.27.1 1
并發連接數前三個面試題
Linux sort命令用于將文本文件內容加以排序
-r 以相反的順序來排序
-n 依照數值的大小排序。
Linux uniq命令用于檢查及刪除文本文件中重復出現的行列
-c或–count 在每列旁邊顯示該行重復出現的次數
數值處理
字符串處理
Rand()返回0和1之間的一個隨機數
awk ‘BEGIN{srand();for(i=0;i<10;i++)print int(rand()*100) }’
Length([s])返回指定字符串的長度
Sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,并將第一個匹配的內容替換為s
[root@centos7 ~]# echo “2008:08:08 08:08:08″| awk ‘sub(/:/,”-“,$1)’
2008-08:08 08:08:08
Sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,并將全部匹配的內容替換為s
[root@centos7 ~]# echo “2008:08:08 08:08:08″| awk ‘gsub(/:/,”-“,$1)’
2008-08-08 08:08:08
Split(s,array,[t]);以r為分隔符,切割字符串s,并將切割后的結果保存至array所表示的數組中,第一個索引值為1,第二個索引值為2
[root@centos7 ~]# netstat -tan |awk ‘/^tcp\>/{split($5,ip,”:”);count[ip[1]]++}END{for(i in count){print i,count[i]}}’
0.0.0.0 5
192.168.27.1 1
^行首牟定,\>詞尾牟定(例如tcp6就不符合),$5遠程主機的IP及端口號,用:做分隔符切割,第五列,放到ip數組中 Ip[1]中存放的是ip地址,count[ip[1]]++ 同一個ip地址放到數組count中,計算數量,結束之后對count做遍歷,打印i,i為count的下標,即ip地址,而count[i]就是對應的ip的數量
[root@centos7 ~]# awk ‘{for(i=1;i<=NF;i++)word[$i]++}END{for(i in word)print i,word[i]}’ /etc/profile
統計每個單詞的數量 ??????每一行讀進來之后,每個單詞作為word的下標,下標一樣加加,不一樣形成新的數組
默認以空格作為分隔符, 最后,進行統計,
[root@centos7~]# awk ‘{if($3==”male”){mnum++;msum+=$2}else{fnum++;fsum+=$2}}
END{printf “male:%d %.2f\nfemale:%d %.2f”,mnum,msum/mnum,fnum,fsum/fnum}’ f1
male:2 95.00
female:2 92.00
[root@centos7 ~]# awk ‘{num[$3]++;sum[$3]+=$2}END{for(sex in num){print sex,num[sex],sum[sex]/num[sex]}}’ f1
female 2 92
male 2 95
[root@centos7 ~]# vim f1
mage ?100 ??male
wang ??90 ??male
zhang ?85 ??female
mo ????99 ??female
使用數組,num[$3]人的個數,使用$3作為它的下標,表現為,num[“male”] ??num[“female”]
num[$3]++表示為male和female人數總和
num[$3]+=$2 ?同一個性別的下標,把成績往相同的下標里累加,最后統計就可以,遍歷
Awk自定義函數
[root@centos7 ~]# awk -f f1.awk
3
[root@centos7 ~]# vim f1.awk
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{a=3;b=2;print max(a,b)}
調用awk函數
調用awk腳本
Awk中調用shell中的命令
[root@centos7 ~]# awk ‘BEGIN{system(“hostname“)}’
centos7.magedu.com
[root@centos7 ~]# awk ‘BEGIN{system(“uname -r“)}’
3.10.0-693.el7.x86_64
[root@centos7 ~]# awk ‘BEGIN{name=”mage”;system(“echo “name)}’
mage ???echo后面有空格
連接數大于3的禁用
ss -nt |awk -F “[ :]+” ‘/^ESTAB/{IP[$(NF-2)]++}END{for(i in IP){if(IP[i] >3)system(“iptables -A INPUT -s “i” -j REJECT”)}}’
向awk腳本傳遞參數
格式:
Awkfile var=value ?var2=value2…inputfile
注意:在BEGIN過程中不可用、直到首行輸入完成以后,變量才可用??梢酝ㄟ^-v參數,讓awk在執行BEGIN之前得到變量的值。命令行中每一個指定的變量都需要一個-v參數
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/90785