运维必会-Awk使用案例总结
数组是用来存储一系列值的变量,可通过索引来访问数组的值。
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访问状态码数量($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:$ 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 i--){printf "%s ",$i}print s} a.txt
100 a xiaoli
110 b xiaoli
120 c xiaoli
$ awk {for(i=NF;i i--)if(i==1)printf $i"\n";else printf $i" "} a.txt
说明:利用NF降序输出,把最后一个域作为第一个输出,然后自减,print s或print ""打印一个换行符
5、从第二列打印到最后
方法1:$ awk {for(i=2;i i++)if(i==NF)printf $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 print $0,f} d
1 one a
2 two b
3 three c
1)替换第二列
$ awk {getline f gsub($2,f,$2)}1 d
1 a
2 b
3 c
2)替换第二列的two
$ awk {getline f 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 i++)print $i}
$ echo "hello" |awk -F {i=1;while(i =NF){print $i;i++}}
h
e
l
l
o
方法2:
$ echo "hello" |awk {split($0,a,"");for(i in a)print a[i]} #无序
l
o
h
e
l
10、统计字符串中每个字母出现的次数
$ echo a,b.c.a,b.a |tr "[,. ]" "\n" |awk -F {for(i=1;i i++)a[$i]++}END{for(i in a)print i,a[i]|"sort -k2 -rn"}
a 3
b 2
c 1
11、第一列排序
$ awk {a[NR]=$1}END{s=asort(a,b);for(i=1;i i++){print i,b[i]}} a.txt
说明:以每行编号作为下标值为$1,并将a数组值放到数组b,a下标丢弃,并将asort默认返回值(原a数组长度)赋值给s,使用for循环小于s的行号,从1开始到数组长度打印排序好的数组。
12、删除重复行,顺序不变
$ awk !a[$0]++ file
博客地址:http://lizhenliang.blog.51cto.com
13、删除指定行
删除第一行:
$ awk NR==1{next}{print $0} file #$0可省略
$ awk NR!=1{print} file
$ sed 1d file
$ sed -n 1!p file
14、在指定行前后加一行
在第二行前一行加txt:
$ awk NR==2{sub(/.*/,"txt\n ")}{print} a.txt
$ sed2s/.*/txt\n / a.txt
在第二行后一行加txt:
$ awk NR==2{sub(/.*/," \ntxt")}{print} a.txt
$ sed2s/.*/ \ntxt/ a.txt
15、通过IP获取网卡名
$ ifconfig |awk -F[: ] /^eth/{nic=$1}/192.168.18.15/{print nic}
16、浮点数运算(数字46保留小数点)
$ awk BEGIN{print 46/100}
$ awk BEGIN{printf "%.2f\n",46/100}
$ echo 46|awk {print $0/100}
$ echo scale=2;46/100 |bc|sed s/^/0/
$ printf "%.2f\n" $(echo "scale=2;46/100" |bc)
结果:0.46
17、替换换行符为逗号
$ cat a.txt
1
2
3
替换后:1,2,3
方法1:
$ awk {s=(s?s","$0:$0)}END{print s} a.txt
说明:三目运算符(a?b:c),第一个s是变量,s?s","$0:$0,第一次处理1时,s变量没有赋值初值是0,0为假,结果打印1,第二次处理2时,s值是1,为真,结果1,2。以此类推,小括号可以不写。
方法2:
$ tr \n , a.txt
方法3:
$ sed :a;N;s/\n/,/;$!b a a.txt
说明:第一个标签a,先读取第一行记录1追加到模式空间,此时模式空间内容是1$,执行$!b($!最后一行不跳转,b是控制流跳转命令)跳转到a标签,继续读取第二行记录2追加到模式空间,因为使用N命令,每个记录以换行符(\n)分割,此时模式空间内容是1\n2$,执行将换行符替换逗号命令,继续跳转到a标签...
方法4:
$ sed :a;$!N;s/\n/,/;t a a.txt
说明:与上面类似,其中t是测试命令,当上一个命令(替换)执行成功才跳转。
方法5:
$ awk {if($0!=3)printf "%s,",$0;else print $0} a.txt
说明:3是文本最后一个数
方法6:
while read line; do
a+=($line)
done a.txt
echo ${a[*]} |sed s/ /,/g
说明:将每行放到数组,然后替换
18、把奇数换行符去掉
$ cat b.txt
string
number
a
1
b
2
$ awk ORS=NR%2?"\t":"\n" b.txt #把奇数行换行符去掉
$ xargs -n2 a.txt #将两个字段作为一行
string number
a 1
b 2
19、费用统计
$ cat a.txt
姓名 费用 数量
zhangsan 8000 1
zhangsan 5000 1
lisi 1000 1
lisi 2000 1
wangwu 1500 1
zhaoliu 6000 1
zhaoliu 2000 1
zhaoliu 3000 1
统计每人总费用、总数量:
$ awk {name[$1]++;number[$1]+=$3;money[$1]+=$2}END{for(i in name)print i,number[i],money[i]} a.txt
zhaoliu 3 11000
zhangsan 2 13000
wangwu 1 1500
lisi 2 3000
20、打印乘法口诀
方法1:
$ awk BEGIN{for(n=0;n++ ){for(i=0;i++ )printf i"x"n"="i*n" ";print ""}}
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
方法2:
#!/bin/bash
for ((i=1;i i++)); do
for ((j=1;j j++)); do
result=$(($i*$j))
#let "result=i*j"
echo -n "$i*$j=$result "
done
echo
done
21、只打印奇数或偶数行
打印奇数行:
方法1:
$ seq 1 5 |awk i=!i
说明:先知道对于数值运算,未定义变量初值为0,对于字符运算,未定义变量初值为空字符串。
读取第一行记录,然后进行模式匹配,i是未定义变量,也就是i=!0,!取反意思。感叹号右边是个布尔值,0或空字符串为假,非0或非空字符串为真,!0就是真,因此i=1,条件为真打印第一条记录。
没有print为什么会打印呢?因为模式后面没有动作,默认会打印整条记录。
读取第二行记录,进行模式匹配,因为上次i的值由0变成了1,此时就是i=!1,条件为假不打印。
读取第三行记录,因为上次条件为假,i恢复初值为0,继续打印。以此类推...
可以看出,运算时并没有判断记录,而是利用布尔值真假判断。
方法2:
$ seq 1 5 |awk NR%2!=0
方法3:
$ seq 1 5 |sed -n 1~2p
说明:步长,每隔一行打印一次
方法4:
$ seq 1 5 |sed -n p;n
说明:先打印第一行,执行n命令读取当前行的下一行2,放到模式空间,后面再没有打印模式空间行操作,所以只保存不打印,同等方式继续打印第三行。
1
3
5
打印偶数行:
$ seq 1 5 |awk !(i=!i)
$ seq 1 5 |awk NR%2==0
$ seq 1 5 |sed -n 0~2p
$ seq 1 5 |sed -n n;p
说明:读取当前行的下一行2,放到模式空间,使用p命令打印模式空间的行,输出2。
分享一些个人总结的阿里云产品使用和运维的经验 个人最近三年阿里云使用和运维经验的总结分享。年底我终于把它写成了一个文档,希望分享给大家。我做的都是基础的运维,没什么高深的内容。可能还会有错误,请大家批评指正!
长达两万字的Elasticsearch分布式集群运维方方面面总结(六) 文章目录 Elasticsearch分布式大数据搜索集群 1.elasticsearch集群介绍 2.elasticsearch集群部署 2.1.192.168.81.210主节点配置 2.1.1.安装elasticsearch 2.1.2.配置node-1主节点 2.1.3.访问node-1节点 2.2.192.168.81.220从节点配置 2.2.1.安装elasticsearch 2.2.2.配置node-2节点 2.2.3.访问node-2节点 2.3.查看集群状态 3.elasticsearch集群状态码 3.1.green状态 3.2.yellow状态 3.3.red状态
【最佳实践】实践总结 阿里云Elasticsearch 智能化运维思路 Elasticsearch 作为一个开箱即用的搜索引擎,其丰富的功能和极低的使用门槛吸引着越来越多的公司和用户选择它作为搜索和数据分析的工具
日常运维过程中总结的安全基线 Redhat Linux操作系统口令复杂度: 采用静态口令进行认证的,口令长度至少6位,并包括数字、小写字母、大写字母和特殊符号四类中至少三类。且5次以内不得设置相同的口令。参考配置: 在/etc/pam.
李振良 6年互联网运维经验,擅长Linux,Python,Docker,MySQL,运维自动化等技术领域。
相关文章
- JVM 调优案例分析1
- 深入浅出 spring-data-elasticsearch - 基本案例详解(三
- SAP UI5 FlexBox Layout 布局的概念和具体使用案例介绍试读版
- 使用扩展方式隐藏SAP Fiori应用某个表格标签页的实际案例
- Soft:软件开发/软件测试/运维的简介(经验/注意事项)、常用工具、案例应用之详细攻略
- Math之ARIMA:基于statsmodels库利用ARIMA算法对太阳黑子年数据(来自美国国家海洋和大气管理局)实现回归预测(ADF检验+LB检验+DW检验+ACF/PACF图)案例
- Python:Python语言的简介(语言特点/pyc介绍/Python版本语言兼容问题(python2 VS Python3))、安装、学习路线(数据分析/机器学习/网页爬等编程案例分析)之详细攻略
- Soft:Eric软件界面的简介、案例应用之详细攻略
- Kubernetes集群RBAC授权案例(三)通过Service Account账号授权实现特定资源的权限分配(四十二)
- 案例:网页自动化截图接口推送到手机(截图维格表数据)
- JDBC增删改查案例讲解
- QT案例实战1 - 从零开始编写一个OCR工具软件 (6) 关于QThread线程的使用
- a18.ansible 生产实战案例 -- docker基于二进制安装harbor-https方式 playbook
- C#读取写入文件的3种方式【案例+源码】
- 【大数据开发运维解决方案】通过降低term在文档出现频率的权重案例教你Solr/Elasticsearch如何自定义Similarity
- 【案例分享】基于CANoe的诊断Coding及Flash实现