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过程中不可用。直到首行输入完成以后,变量才可用。可以通
过-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.178linux.com/98994