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使用案例总结的主要内容,如果未能解决你的问题,请参考以下文章

(转)Awk使用案例总结(运维必会)

Linux三剑客awk的应用对比案例详解

Linux文本处理神器awk实战案例

shell脚本——awk详细介绍(包含应用案例)

Linux三剑客之awk命令详解

文本处理工具AWK简单用法案例