Linux Awk使用案例总结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux Awk使用案例总结相关的知识,希望对你有一定的参考价值。
知识点:
1)数组
数组是用来存储一系列值的变量,可通过索引来访问数组的值。
Awk中数组称为关联数组,因为它的下标(索引)可以是数字也可以是字符串。
下标通常称为键,数组元素的键和值存储在Awk程序内部的一个表中,该表采用散列算法,因此数组元素是随机排序。
数组格式:array[index]=value
1、nginx日志分析
日志格式:‘$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"‘
日志记录:27.189.231.39 - - [09/Apr/2016:17:21:23 +0800] "GET /Public/index/images/icon_pre.png HTTP/1.1" 200 44668 "http://www.test.com/Public/index/css/global.css" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/44.0.2403.157 Safari/537.36" "-"
1)统计日志中访问最多的10个IP
思路:对第一列进行去重,并输出出现的次数
方法1:$ awk ‘{a[$1]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}‘ access.log
方法2:$ awk ‘{print $1}‘ access.log |sort |uniq -c |sort -k1 -nr |head -n10
说明:a[$1]++ 创建数组a,以第一列作为下标,使用运算符++作为数组元素,元素初始值为0。处理一个IP时,下标是IP,元素加1,处理第二个IP时,下标是IP,元素加1,如果这个IP已经存在,则元素再加1,也就是这个IP出现了两次,元素结果是2,以此类推。因此可以实现去重,统计出现次数。
2)统计日志中访问大于100次的IP
方法1:$ awk ‘{a[$1]++}END{for(i in a){if(a[i]>100)print i,a[i]}}‘ access.log
方法2:$ awk ‘{a[$1]++;if(a[$1]>100){b[$1]++}}END{for(i in b){print i,a[i]}}‘ access.log
说明:方法1是将结果保存a数组后,输出时判断符合要求的IP。方法2是将结果保存a数组时,并判断符合要求的IP放到b数组,最后打印b数组的IP。
3)统计2016年4月9日一天内访问最多的10个IP
思路:先过滤出这个时间段的日志,然后去重,统计出现次数
方法1:$ awk ‘$4>="[9/Apr/2016:00:00:01" && $4<="[9/Apr/2016:23:59:59" {a[$1]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}‘ access.log
方法2:$ sed -n ‘/\[9\/Apr\/2016:00:00:01/,/\[9\/Apr\/2016:23:59:59/p‘ access.log |sort |uniq -c |sort -k1 -nr |head -n10 #前提开始时间与结束时间日志中必须存在
4)统计当前时间前一分钟的访问数
思路:先获取当前时间前一分钟对应日志格式的时间,再匹配统计
$ date=$(date -d ‘-1 minute‘ +%d/%b/%Y:%H:%M);awk -vdate=$date ‘$0~date{c++}END{print c}‘ access.log
$ date=$(date -d ‘-1 minute‘ +%d/%b/%Y:%H:%M);awk -vdate=$date ‘$4>="["date":00" && $4<="["date":59"{c++}END{print c}‘ access.log
$ grep -c $(date -d ‘-1 minute‘ +%d/%b/%Y:%H:%M) access.log
说明:date +%d/%b/%Y:%H:%M --> 09/Apr/2016:01:55
5)统计访问最多的前10个页面($request)
$ awk ‘{a[$7]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}‘ access.log
6)统计每个URL访问内容的总大小($body_bytes_sent)
$ awk ‘{a[$7]++;size[$7]+=$10}END{for(i in a)print a[i],size[i],i}‘ access.log
7)统计每个IP访问状态码数量216.www . qixoo.com($status)
$ awk ‘{a[$1" "$9]++}END{for(i in a)print i,a[i]}‘ access.log
8)统计访问状态码为404的IP及出现次数
$ awk ‘{if($9~/404/)a[$1" "$9]++}END{for(i in a)print i,a[i]}‘ access.log
2、两个文件对比
文件内容如下:
$ cat a
1
2
3
4
5
6
$ cat b
3
4
5
6
7
8
1)找出相同记录
方法1:www.51969.com/$ awk ‘FNR==NR{a[$0];next}($0 in a)‘ a b
3
4
5
6
解释前,先看下FNR和NR区别:
$ awk ‘{print NR,$0}‘ a b
1 1
2 2
3 3
4 4
5 5
6 6
7 3
8 4
9 5
10 6
11 7
12 8
$ awk ‘{print FNR,$0}‘ a b
1 1
2 2
3 3
4 4
5 5
6 6
1 3
2 4
3 5
4 6
5 7
6 8
可以看出NR是处理一行记录,编号就会加1,同时也可以看到awk将两个文件当成一个合并后的文件处理。
而FNR则是处理一行记录,编号也会加1,但是,处理到第二个文件时,编号重新计数。
说明:FNR和NR是内置变量。FNR==NR常用于对两个文件处理,这个例子可以理解为awk将两个文件当成一个文件处理。
处理a文件时,FNR是等于NR的,条件为真,执行a[$0],next表达式,意思是将每条记录存放到a数组作为下标(无元素),next是跳出,类似于continue,不执行后面表达式。
执行过程以此类推,直到处理b件时,FNR不等于NR(FNR重新计数是1,NR继续加1是7),条件为假,不执行后面a[$0],next表达式,直接执行($0 in a)表达式,这句意思是处理b文件第一条继续判断是否在a数组中,如果在则打印这条记录,以此类推。
这样可能更好理解些:
$ awk ‘FNR==NR{a[$0]}NR>FNR{if($0 in a)print $0}‘ a b
方法2:
$ awk ‘FNR==NR{a[$0]=1;next}(a[$0])‘ a b #小括号可以不加
$ awk ‘FNR==NR{a[$0]=1;next}(a[$0]==1)‘ a b$ awk ‘FNR==NR{a[$0]=1;next}{if(a[$0]==1)print}‘ a b
$ awk ‘FNR==NR{a[$0]=1}FNR!=NR&&a[$0]==1‘ a b
说明:先要知道后面的a[$0]不是一个数组,而是通过下标(b文件每条记录)来访问a数组元素。如果a[b的一行记录]获取的a数组元素是1,则为真,也就是等于1,打印这条记录,否则获取不到元素,则为假。
方法3:
$ awk ‘ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]==1‘ a b
$ awk ‘FILENAME=="a"{a[$0]=1}FILENAME=="b"&&a[$0]==1‘ a b
说明:ARGIND内置变量,处理文件标识符,第一个文件为1,第二个文件为2。FILENAME也是内置变量,表示输入文件的名字
方法4:$ sort a b |uniq -d
方法5:$ grep -f a b
2)找不同记录(同上,取反)
$ awk ‘FNR==NR{a[$0];next}!($0 in a)‘ a b
$ awk ‘FNR==NR{a[$0]=1;next}!a[$0]‘ a b
$ awk ‘ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]!=1‘ a b
$ awk ‘FILENAME=="a"{a[$0]=1}FILENAME=="b"&&a[$0]!=1‘ a b
7
8
方法2:$ sort a b |uniq -d
方法3:$ grep -vf a b
3、合并两个文件
1)将d文件性别合并到c文件
$ cat c
zhangsan 100
lisi 200
wangwu 300
$ cat d
zhangsan man
lisi woman
方法1:$ awk ‘FNR==NR{a[$1]=$0;next}{print a[$1],$2}‘ c d
zhangsan 100 man
lisi 200 woman
wangwu 300 man
方法2:$ awk ‘FNR==NR{a[$1]=$0}NR>FNR{print a[$1],$2}‘ c d
说明:NR==FNR匹配第一个文件,NR>FNR匹配第二个文件,将$1为数组下标
方法3:$ awk ‘ARGIND==1{a[$1]=$0}ARGIND==2{print a[$1],$2}‘ c d
2)将a.txt文件中服务名称合并到一个IP中
$ cat a.txt
192.168.2.100 : httpd
192.168.2.100 : tomcat
192.168.2.101 : httpd
192.168.2.101 : postfix
192.168.2.102 : mysqld
192.168.2.102 : httpd
$ awk -F: -vOFS=":" ‘{a[$1]=a[$1] $2}END{for(i in a)print i,a[i]}‘ a.txt
$ awk -F: -vOFS=":" ‘{a[$1]=$2 a[$1]}END{for(i in a)print i,a[i]}‘ a.txt
192.168.2.100 : httpd tomcat
192.168.2.101 : httpd postfix
192.168.2.102 : mysqld httpd
说明:a[$1]=$2 第一列为下标,第二个列是元素,后面跟的a[$1]是通过第一列取a数组元素(服务名),结果是$1=$2 $2,并作为a数组元素。
3)将第一行附加给下面每行开头
$ cat a.txt
xiaoli
a 100
b 110
c 120
$ awk ‘NF==1{a=$0;next}{print a,$0}‘ a.txt
$ awk ‘NF==1{a=$0}NF!=1{print a,$0}‘ a.txt
xiaoli a 100
xiaoli b 110
xiaoli c 120
4、倒叙列打印文本
$ cat a.txt
xiaoli a 100
xiaoli b 110
xiaoli c 120
$ awk ‘{for(i=NF;i>=1;i--){printf "%s ",$i}print s}‘ a.txt
100 a xiaoli
110 b xiaoli
120 c xiaoli
$ awk ‘{for(i=NF;i>=1;i--)if(i==1)printf $i"\n";else printf $i" "}‘ a.txt
说明:利用NF降序输出,把最后一个域作为第一个输出,然后自减,print s或print ""打印一个换行符
5、从第二列打印到最后
方法1:$ awk ‘{for(i=2;i<=NF;i++)if(i==NF)prin
tf $i"\n";else printf $i" "}‘ a.txt
方法2:$ awk ‘{$1=""}{print $0}‘ a.txt
a 100
b 110
c 120
6、将c文件中第一列放到到d文件中的第三列
$ cat c
a
b
c
$ cat d
1 one
2 two
3 three
方法1:$ awk ‘FNR==NR{a[NR]=$0;next}{$3=a[FNR]}1‘ c d
说明:以NR编号为下标,元素是每行,当处理d文件时第三列等于获取a数据FNR(重新计数1-3)编号作为下标。
方法2:$ awk ‘{getline f<"c";print $0,f}‘ d
1 one a
2 two b
3 three c
1)替换第二列
$ awk ‘{getline f<"c";gsub($2,f,$2)}1‘ d
1 a
2 b
3 c2)替换第二列的two
$ awk ‘{getline f<"c";gsub("two",f,$2)}1‘ d
1 one
2 b
3 three
7、数字求和
方法1:$ seq 1 100 |awk ‘{sum+=$0}END{print sum}‘
方法2:$ awk ‘BEGIN{sum=0;i=1;while(i<=100){sum+=i;i++}print sum}‘
方法3:$ awk ‘BEGIN{for(i=1;i<=100;i++)sum+=i}END{print sum}‘ /dev/null
方法4:$ seq -s + 1 100 |bc
8、每隔三行添加一个换行符或内容
方法1:$ awk ‘$0;NR%3==0{printf "\n"}‘ a
方法2:$ awk ‘{print NR%3?$0:$0"\n"}‘ a
方法3:$ sed ‘4~3s/^/\n/‘ a
9、字符串拆分
方法1:
$ echo "hello" |awk -F ‘‘ ‘{for(i=1;i<=NF;i++)print $i}‘
$ echo "hello" |awk -F ‘‘ ‘{i=1;while(i<=NF){print $i;i++}}‘
h
e
l
l
o
以上是关于Linux Awk使用案例总结的主要内容,如果未能解决你的问题,请参考以下文章