shell编程之awk

一、awk简介

awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。可以在命令行中使用,但更多是作为脚本来使用。

awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。

awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。

 awk是行处理器: 优势在于处理庞大文件时不会出现内存溢出或是处理缓慢的问题。
 awk处理过程: 依次对每一行进行处理,然后输出,默认分隔符是空格或者tab键 

二、awk的形式语法格式

awk [options] 'commands' filenames

options:

-F 对于每次处理的内容,可以指定一个自定义的分隔符,默认的分隔符是空白字符(空格或 tab 键 )

三、awk工作原理

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

 (1)awk使用一行作为输入,并将这一行赋给变量$0,每一行可称作为一个记录,以换行符结束 
 (2)然后,行被空格分解成字段,每个字段存储在已编号的变量中,从$1开始 
 (3)awk如何知道空格来分隔字段的呢?因为有一个内部变量FS来确定字段分隔符,初始时,FS赋为空格或者是tab 
 (4)awk打印字段时,将以设置的方法,使用print函数打印,awk在打印的字段间加上空格,因为$1,$2间有一个,逗号。逗号比较特殊,映射为另一个变量,成为输出字段分隔符OFS,OFS默认为空格 
 (5)awk打印字段时,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程持续到处理文件结束。

command:

 BEGIN{}                   {}               END{}         filename
 ​
 行处理前的动作          行内容处理的动作     行处理之后的动作    文件名
 ​
 BEGIN{}和END{} 是可选项。
 函数-BEGIN{}:读入文本之前要操作的命令。(也可以设置变量.取值可以不加$)
 {}:主输入循环:用的最多。读入文件之后擦操作的命令。如果不读入文件都可以不用写。
 END{}:文本全部读入完成之后执行的命令。

示例

 [root@awk ~]# awk 'BEGIN{ print 1/2} {print "ok"} END{print "----"}' /etc/hosts
 或者:
 [root@awk ~]# cat /etc/hosts | awk 'BEGIN{print 1/2} {print "ok"} END{print "----"}'
 0.5
 ok
 ok
 ----
 ​

四、记录与字段相关内部变量:

 1.记录和字段
 awk 按记录处理:一行是一条记录,因为awk默认以换行符分开的字符串是一条记录。(默认\n换行符:记录分隔符)
 字段:以字段分割符分割的字符串   默认是单个或多个“ ” tab键。
 ​
 2.awk中的变量
 $0:表示整行;
 NF : 统计字段的个数
 $NF:是number finally,表示最后一列的信息
 RS:输入记录分隔符;
 ORS:输出记录分隔符。
 NR:打印记录号,(行号)
 FNR:可以分开,按不同的文件打印行号。
 FS : 输入字段分隔符,默认为一个空格。  
 OFS 输出的字段分隔符,默认为一个空格。 
 FILENAME 文件名  被处理的文件名称
 $1  第一个字段,$2第二个字段,依次类推...

实战

 FS(输入字段分隔符)---一般简写为-F(属于行处理前)
 [root@awk ~]# cat /etc/passwd | awk 'BEGIN{FS=":"} {print $1,$2}'
 root x
 bin x
 daemon x
 adm x
 lp x
 sync x
 shutdown x
 halt x
 mail x
 [root@awk ~]# cat /etc/passwd | awk -F":" '{print $1,$2}'
 root x
 bin x
 daemon x
 adm x
 lp x
 sync x
 shutdown x
 halt x
 mail x
 ​
 #注:如果-F不加默认为空格区分!
 ===============================================================
 OFS(输出字段分隔符)
 [root@awk ~]# cat /etc/passwd | awk 'BEGIN{FS=":";OFS=".."} {print $1,$2}'
 root..x
 bin..x
 daemon..x
 adm..x
 lp..x
 sync..x
 shutdown..x
 halt..x
 mail..x
 ======================================================================
 1.创建两个文件
 [root@awk ~]# vim a.txt
 love
 love.
 loove
 looooove
 ​
 ​
 [root@awk ~]# vim file1.txt
 isuo
 IPADDR=192.168.246.211
 hjahj123
 GATEWAY=192.168.246.1
 NETMASK=255.255.255.0
 DNS=114.114.114.114
 ​
 NR   表示记录编号, 在awk将行做为记录, 该变量相当于当前行号,也就是记录号
 [root@awk ~]# awk '{print NR,$0}' a.txt file1.txt
 1 love
 2 love.
 3 loove
 4 looooove
 5  
 6 isuo
 7 IPADDR=192.168.246.211
 8 hjahj123
 9 GATEWAY=192.168.246.1
 10 NETMASK=255.255.255.0
 11 DNS=114.114.114.114
 ​
 FNR:表示记录编号, 在awk将行做为记录, 该变量相当于当前行号,也就是记录号(#会将不同文件分开)
 [root@awk ~]# awk '{print FNR,$0}' a.txt file1.txt
 1 love
 2 love.
 3 loove
 4 looooove
 5  
 1 isuo
 2 IPADDR=192.168.246.211
 3 hjahj123
 4 GATEWAY=192.168.246.1
 5 NETMASK=255.255.255.0
 6 DNS=114.114.114.114
 ===========================================================
 RS(输入记录分隔符)
 1.创建一个文件
 [root@awk ~]# vim passwd
 root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologin
 [root@awk ~]# cat passwd | awk 'BEGIN{RS="bash"} {print $0}' 
 root:x:0:0:root:/root:/bin/
 bin:x:1:1:bin:/bin:/sbin/nologin
 ​
 ORS(输出记录分隔符)
 2.对刚才的文件进行修改
 [root@awk ~]# vim passwd
 root:x:0:0:root:/root:/bin/bash
 bin:x:1:1:bin:/bin:/sbin/nologin
 [root@awk ~]# cat passwd | awk 'BEGIN{ORS=" "} {print $0}'
 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin
 ===========================================================
 NF:统计列的个数
 [root@awk ~]# cat /etc/passwd | awk -F":" '{print NF}'
 7
 7
 7
 7
 $NF:打印最后一列
 [root@awk ~]# cat /etc/passwd | awk -F":" '{print $NF}'
 /bin/bash
 /sbin/nologin
 /sbin/nologin
 /sbin/nologin
 /sbin/nologin
 练习1:将文件合并为一行
 [root@awk ~]# cat /etc/passwd | awk 'BEGIN{ORS="" } {print $0}'
 练习2:把一行内容分成多行
 1.首先创建一个文件
 [root@awk ~]# vim d.txt
 root:x:0:0:root:/root:/bin/bash
 [root@awk ~]# cat d.txt | awk 'BEGIN{RS=":"} {print $0}'
 root
 x
 0
 0
 root
 /root

关系运算符号

实现 字符串的完全相等需要使用 ==

字符串需要使用双引号  != 表示不等于
 [root@awk ~]# awk -F":" '$NF == "/bin/bash"' /etc/passwd
 [root@awk ~]# awk -F":" '$1 != "root"' /etc/passwd
  • 比较表达式:
比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。 比较表达式使用 关系运算符,用于比较数字与字符串。
关系运算符有  < 小于 例如  x<y  > 大于  x>y  <= 小于或等于  x<=y  == 等于  x==y  !=不等于  x!=y  >= 大于等于  x>=y

示例

 [root@awk ~]# awk -F":" '$3 == 0' /etc/passwd
 [root@awk ~]# awk -F":" '$3 < 10' /etc/passwd
  • 算术运算:+-*/%(模: 取余)^(幂:2^3)
可以在模式中执行计算,awk都将按浮点数方式执行算术运算
 awk -F: '$3 * 10 > 500' /etc/passwd
  • 逻辑操作符和复合模式
&& 逻辑与, 相当于 并且  ||逻辑或,相当于 或者  ! 逻辑非 , 取反
 awk -F":" '$1~/root/ && $3<=15' /etc/passwd
 awk -F":" '$1~/root/ || $3<=15' /etc/passwd

常见使用

1.打印一个文件中的第2列和第5列

 # cat /etc/passwd | awk -F : '{print $2,$5}'

2.打印指定行指定列的某个字符

 # free -m | awk 'NR==2 {print $2}'

3.统计一个文件的行数

 # cat /etc/passwd | awk '{print NR}'

获取根分区的使用量

4.在awk中使用if条件判断

 ++i:从1开始加,赋值在运算
 i++: 从0开始加,运算在赋值
 if语句:
 {if(表达式){语句;语句;...}}
 ​
 实战案例:
 显示管理员用户姓名
 [root@qfedu ~]# cat /etc/passwd | awk -F":" '{if($3==0) {print $1 " is administrator"}}'
 ​
 统计系统用户数量
 [root@qfedu ~]# cat /etc/passwd | awk -F":" '{if($3>=0 && $3<=1000){i++}} END{print i}'

5.在awk中使用for循环

 每行打印两遍
 [root@qfedu ~]# awk '{for(i=1;i<=2;i++) {print $0}}' /etc/passwd
 root:x:0:0:root:/root:/bin/bash
 root:x:0:0:root:/root:/bin/bash
 bin:x:1:1:bin:/bin:/sbin/nologin
 bin:x:1:1:bin:/bin:/sbin/nologin
 daemon:x:2:2:daemon:/sbin:/sbin/nologin
 daemon:x:2:2:daemon:/sbin:/sbin/nologin

数组遍历--用来统计网站日志,tcp连接状态等。

 ++i:从1开始加,运算在赋值
 i++: 从0开始加,赋值在运算
 #按索引遍历:
 1.先创建一个test文件
 # vim test.txt  #将文件内容的第一个字段作为数组的值,通过索引获取到值
 root:x:0:0:root:/root:/bin/bash
 bin:x:1:1:bin:/bin:/sbin/nologin
 # cat test.txt | awk -F":" '{username[x++]=$1} END{for(i in username) {print i,username[i]}}'
 0 root
 1 bin
 #注意:变量i是索引

真实案例

 #把要统计的对象作为索引,最后对他们的值进行累加,累加出来的这个值就是你的统计数量
 ​
 1. 统计/etc/passwd中各种类型shell的数量
 # cat /etc/passwd | awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }'
 ​
 2.统计nginx日志出现的状态码
 # cat access.log | awk '{stat[$9]++} END{for(i in stat){print i,stat[i]}}'
 ​
 3.统计当前nginx日志中每个ip访问的数量
 # cat access.log | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}'
 ​
 4.统计某一天的nginx日志中的不同ip的访问量
 # cat access.log |grep '28/Sep/2019' | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' 
 ​
 5.统计nginx日志中某一天访问最多的前10个ip
 # cat access.log |grep '28/Sep/2019' | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' |sort -k2 -rn | head -n 2
 sort:排序,默认升序
 -k:指定列数
 -r:降序
 -n:以数值来排序
 ​
 6.统计tcp连接的状态---下去自己查各个状态,包括什么原因造成的!
 # netstat -n | awk '/^tcp/ {tcps[$NF]++} END {for(i in tcps) {print i, tcps[i]}}'
 LAST_ACK 5 (正在等待处理的请求数)
 SYN_RECV 30
 ESTABLISHED 1597 (正常数据传输状态)
 FIN_WAIT1 51
 FIN_WAIT2 504
 TIME_WAIT 1057 (处理完毕,等待超时结束的请求数)

经典案例

 UV与PV统计
 PV:即访问量,也就是访问您商铺的次数;
 例如:今天显示有300 PV,则证明今天你的商铺被访问了300次。
 ================================================================
 UV:即访问人数,也就是有多少人来过您的商铺;  #需要去重
 例如:今天显示有50 UV,则证明今天有50个人来过你的商铺。
 =================================================================
 1.根据访问IP统计UV
 # cat access.log | awk '{print $1}' |sort |uniq -c | wc -l
 uniq:去重
 -c:统计每行连续出现的次数
 2.更具访问ip统计PV
 # cat access.log | awk '{print $1}' |wc -l
 或者是url
 # cat access.log | awk '{print $7}' |wc -l
 3.查询访问最频繁的URL
 # cat access.log | awk '{print $7}'|sort | uniq -c |sort -n -k 1 -r | more
 4.查询访问最频繁的IP
 # cat access.log | awk '{print $1}'|sort | uniq -c |sort -n -k 1 -r | more
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值