awk讲解

1710人浏览 / 0人评论

一、awk简单解释

  awk 是一种很棒的语言,它适合文本处理和报表生成,其语法较为常见,借鉴了某些语言的一些精华,如 C 语言等。在 linux 系统日常处理工作中,发挥很重要的作用,掌握了awk将会使你的工作变的高大上。awk 是三剑客的老大,利剑出鞘,必会不同凡响。

二、BEGIN和END模块

  通常,对于每个输入行,awk 都会执行每个脚本代码块一次。然而,在许多编程情况中, 可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk 允许您定义一个 BEGIN 块。我们在前一个示例中使用了 BEGIN 块。因为 awk 在开始处理输入文
件之前会执行 BEGIN 块,因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。
 
  awk 还提供了另一个特殊块,叫作 END 块。awk 在处理了输入文件中的所有行之后执行这个块。通常,END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

三、awk处理数据的流程

1.进行逐行扫描文件, 从第一行到最后一行

2.寻找匹配的特定模式的行,在行上进行操作

3.如果没有指定处理动作,则把匹配的行显示到标准输出

4.如果没有指定模式,则所有被操作的行都被处理

四、awk语法

awk [options] 'commands' filenames

awk [options] -f awk-script-file filenames

五、awk参数

awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file

 [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value

'  '          引用代码块

BEGIN   初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符

//           匹配代码块,可以是字符串或正则表达式

{}           命令代码块,包含一条或多条命令

;          多条命令使用分号分隔

END      结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息

$0           表示整个当前行

$1           每行第一个字段

NF          字段数量变量

NR          每行的记录号,多文件记录递增

FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始

\t            制表符

\n           换行符

FS          BEGIN时定义分隔符

RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)

~            匹配,与==相比不是精确比较

!~           不匹配,不精确比较

==         等于,必须全部相等,精确比较

!=           不等于,精确比较

&&      逻辑与

||             逻辑或

+            匹配时表示1个或1个以上

/[0-9][0-9]+/   两个或两个以上数字

/[0-9][0-9]*/    一个或一个以上数字

FILENAME 文件名

OFS      输出字段分隔符, 默认也是空格,可以改为制表符等

ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕

-F'[:#/]'   定义三个分隔符

六、awk基础工作

1、匹配root

[root@1 liangzeyu]# awk '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
dockerroot:x:995:992:Docker User:/var/lib/docker:/sbin/nologin

2、-F执行:为分隔符,取除第一列

 awk -F: '{print $1}' /etc/passwd

3、打印匹配root的行的第一列和第三列

[root@1 liangzeyu]# awk -F: '/root/{print $1,$3}' /etc/passwd
root 0
operator 11

[root@1 ~]# awk 'BEGIN{FS=":"} /root/{print $1}' /etc/passwd
root

 4、判断/目录如果大于50000则打印(如果/目录使用了50000以上,则打印剩余空间)

[root@1 ~]# df|awk '/\/$/ {if ($3>50000) print $4}'
14598656

 七、awk内置变量

1、$0表示$1-$$(第一列到最后一列)

 awk '{print $0}' /etc/passwd

2、NR表示行号

[root@1 ~]# awk '{print NR,$0}' /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin 

3、只查看前3行内容

[root@1 ~]# awk 'NR<=3' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin 

4、FNR  当前文件的编号(行号)

awk '{print FNR,$0}' /etc/passwd test.txt 

5、NF  最后一列

[root@1 liangzeyu]# awk -F: '{print $NF}' /etc/passwd
/bin/bash

 6、FS是指定的分隔符(默认分隔符是1个空格)

[root@1 liangzeyu]# awk -F: '/root/{print $1,$3}' /etc/passwd
root 0
operator 11

[root@1 ~]# awk 'BEGIN{FS=":"} /root/{print $1}' /etc/passwd
root

 7、指定:号和多个空格为分割符

 awk -F'[:| ]+' '{print $1}' /etc/passwd

 8、OFS执行输出字段分隔符

[root@1 liangzeyu]# awk 'BEGIN{FS=":";OFS="+++"} /root/{print $1,$2}' /etc/passwd
root+++x
operator+++x

[root@1 liangzeyu]# awk 'BEGIN{FS=":"} /root/{print $1"+++"$2}' /etc/passwd
root+++x
operator+++x

 9、RS输入记录分隔符,默认为换 行符

awk -F: 'BEGIN{RS=" "} {print $0}' /etc/hosts

10、`ORS`将文件以空格为分割每一行合并为一行 

awk -F: 'BEGIN{ORS=" "} {print $0}' /etc/hosts

 11、函数输出 

 awk -F: '{print "用户是:" $1 "\t 用户uid: " $3  "\t 用户gid:" $4}' /etc/passwd

 12、第一列是root的,显示整行内容

[root@1 liangzeyu]# awk -F: '$1 ~ /root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
dockerroot:x:995:992:Docker User:/var/lib/docker:/sbin/nologin

13、第一列不是root的。显示整行内容

awk -F: '$1 !~ /root/{print $0}' /etc/passwd
 

八、比较运算符

运算符 含义    示例 

<       小于          x<y

<=      小于或等于     x<=y

==      等于          x==y

!=      不等于         x!=y

>=      大于等于        x>=y

>       大于          x>y

uid0的列出来

[root@Shell ~]# awk -F ":" '$3==0' /etc/passwd

uid小于10的全部列出来

[root@Shell ~]# awk -F: '$3 < 10' /etc/passwd

用户登陆的shell等于/bin/bash

[root@Shell ~]# awk -F: '$7 == "/bin/bash" ' /etc/passwd

第一列为alice的列出来

[root@Shell ~]# awk -F: '$1 == "alice" ' /etc/passwd

alice的用户列出来

[root@Shell ~]# awk -F: '$1 ~ /alice/ ' /etc/passwd

[root@Shell ~]# awk -F: '$1 !~ /alice/ ' /etc/passwd

磁盘使用率大于多少则,则打印可用的值

[root@Shell ~]# df |awk '/\/$/'|awk '$3>1000000 {print $4}'

 九、条件表达式

[root@Shell ~]# awk -F: '$3>300 {print $0}' /etc/passwd

[root@Shell ~]# awk -F: '{if($3>300) print $0}' /etc/passwd

[root@Shell ~]# awk -F: '{if($3>5555){print $3} else {print $1}}' /etc/passwd

 十、运算表达式

[root@Shell ~]# awk -F: '$3 * 10 > 500000' /etc/passwd

[root@Shell ~]# awk -F: 'BEGIN{OFS="--"} { if($3*10>50000) {print $1,$3} } END {print "打印ok"}' /etc/passwd

[root@Shell ~]# awk '/southem/{print $5 + 10}' datafile

[root@Shell ~]# awk '/southem/{print $5 + 10.56}' datafile

[root@Shell ~]# awk '/southem/{print $8 - 10}' datafile

[root@Shell ~]# awk '/southem/{print $8 / 2 }' datafile  

[root@Shell ~]# awk '/southem/{print $8 * 2 }' datafile

[root@Shell ~]# awk '/southem/{print $8 % 2 }' datafile

 十一、逻辑操作符和复合模式  

&&逻辑与 || 逻辑或  !逻辑非 

匹配用户名为root并且打印uid小于15的行

[root@Shell ~]# awk -F: '$1~/root/ && $3<=15' /etc/passwd

匹配用户名为rootuid大于5000

[root@Shell ~]# awk -F: '$1~/root/ ||   $3>=5000' /etc/passwd

十二、判断语句

if语句格式:{ if(表达式){语句;语句;... }}  

打印当前管理员用户名称

[root@Shell ~]# awk -F: '{ if($3==0){print $1 "is adminisitrator"} }' /etc/passwd

统计系统用户数量

[root@Shell ~]# awk -F: '{ if($3>0 && $3<1000){i++}} END {print i}' /etc/passwd

 

统计普通用户数量

[root@Shell ~]# awk -F: '{ if($3>1000){i++}} END {print i}' /etc/passwd

 

 

if...else 语句格式: {if(表达式){语句;语句;... else{语句;语句;...}}

 

 

# awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd

# awk -F: '{if($3==0) {count++} else{i++} }' /etc/passwd

# awk -F: '{if($3==0){count++} else{i++}} END{print " 管理员个数: "count ; print " 系统用户数: "i}' /etc/passwd

 

if...else if...else 语句格式:

{if(表达式 1){语句;语句;... else if(表达式 2){语句;语句;. .. else{语句;语句;... }

 

 

[root@Shell ~]# awk -F: '{ if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print i;print j;print k}' /etc/passwd

[root@Shell ~]# awk -F: '{ if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print "管理员个数"i; print "系统用户个数" j; print "系统用户个 " }' /etc/passwd

管理员个数1

系统用户个数29

系统用户个数69

十三、while循环语句

[root@Shell ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'

[root@Shell ~]# awk -F: '{i=1; while(i<=NF){print $i; i++}}' /etc/passwd

[root@Shell ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd

[root@Shell ~]#cat b.txt

111 222

333 444 555

666 777 888 999

[root@Shell ~]# awk '{i=1; while(i<=NF){print $i; i++}}' b.txt

十四、for循环

[root@Shell ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }'

将每行打印 10

[root@Shell ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd

[root@Shell ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd

[root@Shell ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd

十五、数组

1、统计`/etc/passwd`中各种类型`shell` 的数量 

awk -F: '{shells[$NF]+ +} END{ for(i in shells){print i,shells[i]} }' /etc/passwd 

 2、站访问状态统计<当前时实状态ss>  

[root@Shell ~]# ss -an|awk '/:80/{tcp[$2] ++} END {for(i in tcp){print i,tcp[i]}}' 

3、 统计当前访问的每个IP的数量<当前时实状态 netstat,ss> 

ss -an|awk -F ':' '/:80/{ips[$(NF-1)]++} END {for(i in ips){print i,ips[i]}}' 

 十六、日志分析 

1、统计2018年01月25日,当天的PV量

[root@Shell ~]# grep "25/Jan/2018" log.bjstack.log |wc -l

[root@Shell ~]# awk "/25\/Jan\/2018/" log.bjstack.log |wc -l

[root@Shell ~]# awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips) {sum+=ips[i]} {print sum}}' log.bjstack.log

2、统计15-19点的pv

[root@Shell ~]# awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00 {print $0}"' log.bjstack.log |wc -l

3、统计2018年01月25日,一天内访问最多的10个IP* 

[root@Shell ~]# awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){ print ips[i],i}}' log.bjstack.log |sort -rn|head

4、统计15-19点访问次数最多的10个IP

[root@Shell ~]# awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00"' log.bjstack.log |awk '{ips[$1]++} END {for(i in ips){print ips[i],i}}'|sort -rn|head 

5、​​​​​​​统计2018年01月25日,访问大于100次的IP 

[root@Shell ~]# awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){if(ips[i]>10){print i,ips[i]}}}' log.bjstack.log

6、​​​​​统计2018年01月25日,访问最多的10个页面($request top 10)

[root@Shell ~]# awk '/25\/Jan\ /2018/ {request[$7]++} END {for(i in request){print request[i],i}}' log.bjstack.log |sort -rn| head

7、​​​​​​​​​​​​统计2018年01月25日,每个URL访问内容总大小($body_bytes_sent)* 

awk '/25\/Jan\/2018/ {request[$7]++;size[$7]+=$10} END {for(i in request){print request[i],i,size[i]}}' log.bjstack.log |sort -rn|head

8、​​​​​​​统计2018年01月25日,每个IP访问状态码数量($status)* 

awk '{ip_code[$1 " " $9]++} END {for(i in ip_code){print ip_code[i],i}}' log.bjstack.log|sort -rn|head

​​​​​​​9、统计2018年01月25日,访问状态码为404及出现的次数($status)* 

grep "404" log.bjstack.log |wc -l

 awk '{if($9=="404") code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

10、​​​​​​​统计20180125,8:30-9:00访问状态码是404*

 awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00" && $9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

 awk '$9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

11、​​​​​​​统计2018年01月25日,各种状态码数量,统计状态码出现的次数 

[root@Shell ~]# awk '{code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

[root@Shell ~]# awk '{if($9>=100 && $9<200) {i++}

else if ($9>=200 && $9<300) {j++}

else if ($9>=300 && $9<400) {k++}

else if ($9>=400 && $9<500) {n++}

else if($9>=500) {p++}}

END{print i,j,k,n,p,i+j+k+n+p}' log.bjstack.log

 

  

全部评论