awk控制語句
?{ statements;… } 組合語句
?if(condition) {statements;…}
?if(condition) {statements;…} else {statements;…}
?while(conditon) {statments;…}
?do {statements;…} while(condition)
?for(expr1;expr2;expr3) {statements;…}
?break
?continue
?delete array[index]
?delete array
?exit
?
awk控制語句if-else
? 語法:if(condition){statement;…}[else statement]? 單分支[及雙分支]
if(condition1){statement1}else if(condition2){statement2}
else{statement3}?? 多分支
? 使用場景:對awk取得的整行或某個字段做條件判斷
? 示例:
awk -F: ‘{if($3>=1000)print $1″:”$3}’ /etc/passwd?? 顯示
awk -F: ‘{if($NF==”/bin/bash”)print $1}’ /etc/passwd? 只顯示最后一個字段是/bin/bash的行的第一個字段
awk ‘{if(NF>5)print $0}’ /etc/fstab? 意思是只顯示每行字段數大于5的行
awk -F: ‘{if($3>=1000){printf “common user:%s\n”,$1}else{printf “root or sysuser:%s\n”,$1}}’ /etc/passwd?
對每行進行判斷,如果uid大于等于1000,則顯示common user ,否則顯示root or sysuse
?
awk -F: ‘{if($3>=1000) printf “Common user: %s\n”,$1; else printf “root or Sysuser: %s\n”,$1}’ ?/etc/passwd? 注意:如果if和else后面只有一條語句,可以不寫大括號,但是如果后面跟多條語句必須寫大括號,建議寫大括號!
df -h|awk -F% ‘/^\/dev\/sd/{print $1}’|awk ‘$NF>=80{print $1,$5}’
意思是如果分區利用率大于80,則顯示分區名及分區利用率。
awk ‘BEGIN{test=100;if(test>90){print “very good”}else if(test>60){print “good”}else{print “no pass”}}’? 顯示
?
awk控制語句
?while循環 ?(對行里的字段進行循環,awk自帶行循環功能)
?語法:while(condition){statement;…}
?條件“真”,進入循環;條件“假”,退出循環
?使用場景:
對一行內的多個字段逐一類似處理時使用
對數組中的各元素逐一處理時使用
?示例:
awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF){{print $i,length($i)};i++}}’ /etc/grub2.cfg? 顯示linux16那一行的每個字段及每個字段的長度
^[[:space:]]* 意思是以空格開頭,空格可有可無
awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=10){print $i,length($i)};i++}}’ /etc/grub2.cfg
意思是顯示linux16那一行中,字段長度大于等于10的字段及字段長度
?
awk ‘BEGIN{print length(“dadsad”)}’? 顯示字符串的長度,必須使用雙引號引上!
awk ‘BEGIN{print length(“dadsad我們“)}’? 顯示8
?
awk控制語句
?do-while循環
?語法:do{statement;…}while(condition)即do{循環體}while(條件)
?意義:無論真假,至少執行一次循環體
?示例:用awk方式實現1+2+3+..100
方法一:
?awk ‘BEGIN{total=0;i=0;do{total+=i;i++;}while(i<=100);print total}’
方法二:awk ‘BEGIN{i=1;while(i<=100){sum=sum+i;i++};print sum}’ 或者
awk ‘BEGIN{i=1;while(i<=100){sum=sum+i;i++};{print sum}}’
?
awk控制語句
?for循環
?語法:for(expr1;expr2;expr3) {statement;…}
?常見用法:for(variable assignment;condition;iteration process)
{for-body}
?特殊用法:能夠遍歷數組中的元素
語法:for(var in array) {for-body}
?示例:
awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}’ /etc/grub2.cfg
例題:用awk加for循環方式實現1+2+3+..100
awk ‘BEGIN{for(i=1;i<=100;i++){sum=sum+i};{print sum}}’
注意:在awk語句內的變量,在awk語句結束后就消失了,與bash不同?。?!
?
性能比較
?time (awk ‘BEGIN{ total=0;for(i=0;i<=1000000;i++){total+=i;};print total;}’)? 效率最高
?time(total=0;for i in {1..1000000};do total=$(($total+i));done;echo $total)
?time(for ((i=0;i<=1000000;i++));do let total+=i;done;echo $total)效率最低
? time(seq -s + 1000000 | bc)
awk控制語句
?switch語句
?語法:switch(expression) {case VALUE1 or /REGEXP/:statement1; case
VALUE2 or /REGEXP2/:statement2; …; default:statementn}? 注意格式冒號
switch后面跟的表達式如果等于VALUE1 or /REGEXP/,則執行statement1,如果等于VALUE2 or /REGEXP2/,則執行statement2,如果都不等于,則執行statementn
?break和continue
?awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}’? 顯示奇數和
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}’
意思是當加到66時結束循環(break)
練習:計算1+2+3+..100中的奇數和及偶數和
奇數和:? 顯示2500
awk ‘BEGIN{for(i=1;i<=100;i++){if(i%2==0){continue}else{sum=sum+i}}
print sum}’
偶數和:顯示2550
awk ‘BEGIN{for(i=1;i<=100;i++){if(i%2==1){continue}else{sum=sum+i}};
print sum}’
?
awk控制語句
?break [n]
?continue [n]
?next:
提前結束對本行處理而直接進入下一行處理(awk自身循環)
awk -F: ‘{if($3%2!=0) next; print $1,$3}’ /etc/passwd或者
awk -F: ‘{if($3%2!=0) next; {print $1,$3}}’ /etc/passwd
意思是如果第三列是奇數,則不做任何處理,直接進入下一行,說白了就是顯示第三列是偶數行的第一和第三字段
?
awk -F: ‘{if($3>10){print $1,$3};if($3<100){print $1,$3}}’ /etc/passwd
注意:這樣寫,分號兩側的語句是邏輯或的關系!這條代碼的意思是顯示全部行的$1和$3
awk -F: ‘{if($3>10&&$3<100){print $1,$3}}’ /etc/passwd
這樣寫才能實現并且的邏輯關系,顯示$3大于10小于100的行的$1和$3
?
awk數組(awk中數組就是關聯數組,沒有普通數組的說法)
?關聯數組:array[index-expression]
?index-expression:
?(1) 可使用任意字符串;字符串要使用雙引號括起來
?(2) 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,并將其值
初始化為“空串”!
?若要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷,index代表下表變量,array代表數組名稱!
?示例:
?weekdays[“mon”]=”Monday”?? 在awk中給數組賦值的方式,雙引號必須加
?awk ‘BEGIN{weekdays[“mon”]=”Monday”;weekdays[“tue”]=”Tuesday”;
print weekdays[“mon”]}’
?awk ‘!arr[$0]++’ f1
去掉重復行!
?awk ‘{!arr[$0]++;print $0, arr[$0]}’ f1
例如:為數組賦值并打印
awk ‘BEGIN{title[“ceo”]=”mage”;tile[“coo”]=”zhangsir”;{print title[“ceo”]}}’
顯示
例如:vim f1
awk ‘!arr[$0]++’ f1
!arr[$0]++的意思是先對arr[$0]取反,同時arr[$0]=arr[$0]+1
邏輯是:
當第一行讀入,arr[“aaa”]= “”,
此時!arr[“aaa”]=1,arr[“aaa”]=arr[“aaa”]+1=””+1=1,說明arr[“aaa”]=1,
!arr[“aaa”]=1為真,真則執行后面隱藏掉的print $0,打印第一行。
第二行、第三行的執行結果同第一行
第四行時,arr[“aaa”]=1,!arr[“aaa”]=0,為假,則不執行print $0,但arr[“aaa”]=1+1=2
說白了,這個命令的意思是去掉重復行!
sort -u f1 這個命令也可以去重!
awk ‘!++arr[$0]’ f1? 什么都不打印
邏輯是第一行讀入時arr[“aaa”]=””,先執行++arr[“aaa”],則
arr[“aaa”]=””+1=1,取反則為0,假,則不執行print $0,以此類推
?
awk數組
?若要遍歷數組中的每個元素,要使用for循環
?for(var in array) {for-body}
?注意:var會遍歷array的每個索引
?示例:
?awk ‘BEGIN{weekdays[“mon”]=”Monday”;weekdays[“tue”]
=”Tuesday”;for(i in weekdays) {print weekdays[i]}}‘
?netstat -tan | awk ‘/^tcp/{state[$NF]++}END
{for(i in state) { print i,state[i]}}’
?awk ‘{ip[$1]++}END{for(i in ip) {print i,ip[i]}}’ /var/log/httpd/access_log
?
練習:運用for遍歷來打印數組元素!
awk ‘BEGIN{title[“ceo”]=”mage”;title[“coo”]=”zhangsir”;
title[“cto”]=”wang”;for(i in title){print title[i]}}’? 顯示如圖
練習:
systemctl start httpd
netstat -nat
ab -c 100 -n 2000 http://192.168.30.7:9527/? 并發訪問
bc命令需要安裝包yum install httpd-tools
如果想統計每種狀態有多少次,如何實現?
netstat -tan | awk ‘/^tcp/{state[$NF]=state[$NF]+1}END{for(i in state){print i,state[i]}}’
例如:統計/var/log/httpd/access_log哪些ip在訪問,分別訪問了多少次?
cat access_log | awk ‘/^[0-9]+/{ip[$1]=ip[$1]+1}END{for(i in ip){print i,ip[i]}}’
例如:編寫腳本,分析上題結果,凡連接數超過1000的地址,將其放入防火墻中:
iptables -A INPUT -s 172.20.111.65 -j REJECT 將172.20.111.65扔到防火墻里
答:方法一:cat access_log | awk ‘/^[0-9]+/{ip[$1]=ip[$1]+1}END
{for(i in ip){if(ip[i]>10000){print i}}}’ | while read line;do iptables -A INPUT -s $line -j REJECT;done
查詢將哪些地址放入防火墻內:iptables -vnL
清空防火墻內的地址:iptables -F
方法二:cat access_log | awk ‘/^[0-9]+/{ip[$1]=ip[$1]+1}END{for(i in ip){print i,ip[i]}}’ | awk ‘{if($2>=1000){system(” iptables -A INPUT -s ” $1 ” -j REJECT “)}}’
例如:顯示上題中連接數排名前十的ip地址
cat access_log | awk ‘/^[0-9]+/{ip[$1]=ip[$1]+1}END{for(i in ip){print i,ip[i]}}’ | sort -k 2 -nr | head
注意:sort -k 2 -nr意思是按第二列的數字排序,而且是倒序!
例如:統計文檔/etc/rc.sysinit內每個單詞及出現的次數 基本格式awk ‘{}END{}’
awk ‘{for(i=1;i<=NF;i++){word[$i]=word[$i]+1}}END{for(j in word){print j,word[j]}}’ /etc/rc.sysinit
例如:有一個成績表,格式是姓名、分數、性別,如下圖
統計男生的平均成績和女生的平均成績?
awk ‘{if($3==”m”){sum_m=sum_m+$2;num_m=num_m+1}else{sum_f=sum_f+$2;
num_f=num_f+1}}END{printf “male:%.2f\nfemale:%.2f\n”,sum_m/num_m,
sum_f/num_f}’ score.txt
注意:下圖寫法不對,END內語句如果不遍歷,那么是不能引用數組的?。?!
用數組寫
awk ‘{sum[$3]=sum[$3]+$2;num[$3]=num[$3]+1}END{for(i in num){
print i,sum[i]/num[i]}}’ score.txt
?
awk函數(引用函數的時候必須帶小括號!)
? 數值處理:
rand():返回0和1之間的一個隨機數,說是隨機數,但實際上是一個固定的0.237788,如果想生成0-1的任何一個隨機數,需要借助srand()這個種子才可以.
例如:awk ‘BEGIN{print rand()}’? 只顯示0.237788
awk ‘BEGIN{srand();print rand()}’? 才能實現0-1之間的隨機數
awk ‘BEGIN{srand();print int(rand()*100)}’ 顯示100之內隨機的整數
awk ‘BEGIN{srand();for(i=1;i<=100;i++){print int(rand()*100)}}’
意思是顯示100個100以內的隨機整數 ?注意:srand()函數就不能往for里面放,只能放BEGIN后面!
? 字符串處理:
?length([s]):返回指定字符串的長度
?sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,并將第一個匹配的內容替換為s
echo “2008:08:08 08:08:08″ | awk ‘sub(/:/,”-“,$1)’
gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,并全部替換為s所表示的內容
echo “2008:08:08 08:08:08″ | awk ‘gsub(/:/,”-“,$1)’
split(s,array,[r]):以r為分隔符,切割字符串s,并將切割后的結果保存至array所表示的數組中,第一個索引值為1,第二個索引值為2,…
netstat -tan | awk ‘/^tcp\>/{split($5,ip,”:”);conut[ip[1]]=conut[ip[1]]+1}
END{for(i in conut){print i,count[i]}}’
例如head -n1 /etc/passwd | awk ‘{split($0,arr,”:”)}END{for(i in arr){print i,arr[i]}}’
?
awk函數
? 自定義函數
? 格式:
function 函數名 (參數1,參數2..參數N){
?? 語句
?? return 表達式
}
function name ( parameter, parameter, … ) {
statements
return expression
}
? 示例:
cat fun.awk
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
BEGIN{a=3;b=2;print max(a,b)}
awk –f fun.awk? 顯示的是3
或者
cat fun.awk
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
BEGIN{print max(a,b)}
awk -v a=100 -v b=200–f fun.awk? 顯示的是200
?
awk中調用shell命令
?system命令
?空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用
空格分隔,或者說除了awk的變量外其他一律用“”引用起來。
awk BEGIN'{system(“hostname”)}’
awk ‘BEGIN{score=100; system(“echo your score is ” score) }’
注意:后面的的雙引號之前有一個空格!
awk腳本
?將awk程序寫成腳本,直接調用或執行
?示例:
cat f1.awk
{if($3>=1000)print $1,$3}
awk -F: -f f1.awk /etc/passwd
或者vim f2.awk
#!/bin/awk –f
#this is a awk script
{if($3>=1000)print $1,$3}
chmod +x f2.awk
f2.awk –F: /etc/passwd
?
?
?
?
?
向awk腳本傳遞參數
?格式:
awkfile var=value var2=value2… Inputfile
?注意:在BEGIN過程中不可用。直到首行輸入完成以后,變量才可用??梢酝?/span>
過-v 參數,讓awk在執行BEGIN之前得到變量的值。命令行中每一個指定的變
量都需要一個-v參數(建議都加-v選項,-v具有通用性)
?示例:
cat test.awk
#!/bin/awk –f
{if($3 >=min && $3<=max)print $1,$3}
chmod +x test.awk
test.awk -F: -v min=100 -v max=200 /etc/passwd
練習:提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有數字
echo “Yd$C@M05MB%9&Bdh7dq+YVixp3vpw” | awk ‘gsub(/[^0-9]/,””,$0)’或者
echo “Yd$C@M05MB%9&Bdh7dq+YVixp3vpw” | awk ‘gsub(/[^[:digit:]]/,””,$0)’
注意:正則表達式里排除數字[^0-9]或者[^[:digit:]]。[^[0-9]]寫法錯誤
練習
解決DOS攻擊生產案例:根據web日志或者或者網絡連接數,監控當某個IP
并發連接數或者短時內PV達到100,即調用防火墻命令封掉對應的IP,監控頻
率每隔5分鐘。防火墻命令為:iptables -A INPUT -s IP -j REJECT
并發連接數使用netstat -nt 查看,通過web日志是使用命令
cat /var/log/httpd/access_log
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/98994