Chinaunix首页 | 论坛 | 博客
  • 博客访问: 403312
  • 博文数量: 105
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 889
  • 用 户 组: 普通用户
  • 注册时间: 2016-01-23 21:45
个人简介

目前在一家电信公司就职报表开发工程师,2010年开始从事运维方面的工作,期间从事过业务维护工程师、自动化运维工程师,2016年转为报表开发工程师。有耐心,抗压力、爱折腾,喜欢研究自动化工具。

文章分类

全部博文(105)

分类: 系统运维

2019-04-08 19:10:12

1、Awk是什么
awk是一种编程语言,是在linux系统中对文本文件进行数据分析的行处理器,实际上,awk有多个版本,如:awk、nawk、gawk等。今天我们讲的是centOS系统自带的gawk。
2Awk命令形式
awk [-F|-f|-v] ‘BEGIN{} //{command1;command2} END{}’ file
[-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
'  '         引用代码块
BEGIN   初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符(
例如:[root@VM_172_116_centos ~]# echo"hello the:world" |awk 'BEGIN{FS="[ :]"} {print $2}')
//           匹配代码块,可以是字符串或正则表达式
{}           命令代码块,包含一条或多条命令
;          多条命令使用分号分隔
END      结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信
特殊要点:
$0          表示整个当前行
$1          每行第一个字段
NF         字段数量变量
NR         每行的记录号,多文件记录递增
FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
\t           制表符
\n          换行符
FS         BEGIN时定义分隔符
RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~           匹配,与==相比不是精确比较
!~          不匹配,不精确比较
==         等于,必须全部相等,精确比较
!=          不等于,精确比较
&&      逻辑与
||            逻辑或
+           匹配时表示1个或1个以上
/[0-9][0-9]+/   两个或两个以上数字
/[0-9][0-9]*/    一个或一个以上数字
OFS        输出字段分隔符, 默认也是空格,可以改为制表符等
ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]'   定义三个分隔符
理解awk  ‘{code}1’ 中的“1”是干什么的?
一个完整的awk语句为:awk ‘[patten]{action}….‘ ,其中patten缺省值为1,action缺省值是{print},那么awk ‘1’完整写法就是awk ‘1{print}’;同理awk ‘{print}’ 完整写法是awk ‘1{print}’。
3、Awk工作流程
                              
3.1、EGIN { commands} 语句块中的语句。
3.2、stdin 中读取一行,然后执行 pattern { commands } 。重复这个过程,直到文件全部被读取完毕。
3.3、入流末尾时,执行 END {commands } 语句块。
4、Awk基本使用
print & $0
print 是awk打印指定内容的主要命令
awk '{print}'  /etc/passwd   ==  awk '{print $0}'  /etc/passwd  
awk '{print ""}' /etc/passwd                                           //不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本
awk '{print "a"}'  /etc/passwd                                        //输出相同个数的a行,一行只有一个a字母
-F指定分隔符
$1 指指定分隔符后,第一个字段,$3第三个字段, \t是制表符
一个或多个连续的空格或制表符看做一个定界符,即多个空格看做一个空格
awk -F":" '{print $1}' /etc/passwd
awk -F":" '{print $1 $3}' /etc/passwd                      //$1与$3相连输出,不分隔
awk -F":" '{print $1,$3}' /etc/passwd                      //多了一个逗号,$1与$3使用空格分隔
awk -F":" '{print $1 "" $3}'  /etc/passwd                 //$1与$3之间手动添加空格分隔
//匹配代码块
//纯字符匹配   !//纯字符不匹配   ~//字段值匹配   !~//字段值不匹配   ~/a1|a2/字段值匹配a1a2   
awk '/ yunweizhrt/' /etc/passwd
awk '/ yunweizhrt/{print }' /etc/passwd
awk '/ yunweizhrt/{print $0}' /etc/passwd                  //三条指令结果一样
IF语句
必须用在{}中,且比较内容用()扩起来
awk -F: '{if($1~/yunweizhrt/) {print $1}}' /etc/passwd                                  //全写
awk -F: '{if($1~/yunweizhrt/) {print $1}else {print $2}}' /etc/passwd           //if...else...
awk -F: '{if($3>100) print "large"; else print"small"}' /etc/passwd
small
small
small
large
small
small
awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print"large"} else {B++; print "small"}} END{printA,"\t",B}' /etc/passwd
                                                                                                                 //ID大于100,A加1,否则B加1
另一种形式
awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd
awk -F: '{print ($3>100 ?$3":\tyes"3":\tno")}'  /etc/passwd
看一个例子短网址145:
[root@VM_105_92_centos shelldir]# more  nginx_status_monitor_145.sh
#!/bin/sh
. /home/yunweizhrt/.bash_profile
file_date=`date '+%Y-%m-%d %T'`
cd /home/yunweizhrt/shelldir
status_nginx=`cat  /home/wwwlogs/access_suo_im.log|awk '{print$9}'|sort -n|uniq -c|sort -nr|head -6|awk '{print $2,$1}'|awk'BEGIN{ORS="|"}{print $0}END{print " "}'`
success_rate=`cat  /home/wwwlogs/access_suo_im.log|awk '{print$9}'|sort -n|uniq -c|sort -nr|awk '{print $2,$1}'|awk'{sun_count+=$2;if($1==301){suss_count+=$2}else if($1==302){
suss_count+=$2} elseif($1==200){suss_count+=$2} } END{printf("%.f\n",suss_count/sun_count*100)}'`
条件表达式
==   !=   >   >=  
awk -F":" '$1=="yunweizhrt"{print$3}' /etc/passwd  
awk -F":" '$1!="yunweizhrt"{print$3}' /etc/passwd                 //不等于
awk -F":" '$3>1000{print $3}'/etc/passwd                     //大于
awk -F":" '$3>=100{print $3}'/etc/passwd                    //大于等于
awk -F":" '$3<1{print $3}'/etc/passwd                           //小于
awk -F":" '$3<=1{print $3}'/etc/passwd                        //小于等于
逻辑运算符 用的少一些
&& ||
awk -F: '$1~/yunweizhrt/ && $3>8{print }' /etc/passwd         //逻辑与,$1匹配mail,并且$3>8
awk -F: '{if($1~/yunweizhrt/ &&$3>8) print }' /etc/passwd
awk -F: '$1~/yunweizhrt/ || $3>1000{print }' /etc/passwd       //逻辑或
awk -F: '{if($1~/yunweizhrt/ || $3>1000)print }' /etc/passwd
数值运算
awk -F: '$3 > 100' /etc/passwd   
awk -F: '/yunweizhrt /{print $3+10}' /etc/passwd                   //第三个字段加10打印
awk -F: '/yunweizhrt /{print $3-$4}' /etc/passwd                            //减法
awk -F: '/yunweizhrt/{print $3*$4}' /etc/passwd                            //求乘积
awk '/yunweizhrt/{print $2/1024}' /proc/meminfo                 //除法
while语句
awk -F: 'BEGIN{i=1} {while(i
[root@VM_122_26_centos ~]# cat /etc/passwd|head -1
root:x:0:0:root:/root:/bin/bash
[root@VM_122_26_centos ~]# cat /etc/passwd|head -1|awk -F: 'BEGIN{i=1}{while(i
7 root 1
7 x 2
7 0 3
7 0 4
7 root 5
7 /root 6
数组
此处要说一下linux shell 数组
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printi,"\t",a}'
以上部分awk的基础知识。
5、Awk数据分析
我们大家都知道少量的数据在数据库(例如mysql、oracle)中分析很容易,就是写sql语句过滤,什么where  group by count sum having等,但是一些日志文件是不入库的,我们有时候也有需求需要进行数据的分,例如:分析接口日志返回码情况,通常大数据分析之前需要进行试探性的数据分析,这些数据大部分都是文本存储的,此时就会用到linux的分析命令awk。
刚才给大家讲了awk的基本使用,现在我们就看看awk的数据分析吧。
5.1、awk实现where查询
cd /home/yunweizhrt/tomcat-logs/suolink-cn/dwz-web-jump/visit
[root@VM_236_62_centos visit]# cat  2019-02-27_15.log|awk -F '[:,]''{if($4="4r4rze")print $0}'
5.2、awk实现mysql的distinct去重记录
[root@VM_0_8_centos ~]# cat 111.txt
1
2
3
3
2
1
44
1
[root@VM_0_8_centos ~]# cat 111.txt |awk'!a[$0]++'
1
2
3
44
[root@VM_0_8_centos ~]#
5.3、awk实现mysql的limit
[root@VM_122_26_centos visit]# cat2019-02-27_15.log |awk 'NR<=2{print $0}'
5.4、awk实现mysql的sum
[root@VM_0_8_centos ~]# cat 111.txt |awk'BEGIN{sum=0}{sum+=$1}END{print sum}'
57
5.5、awk实现mysql的max
[root@VM_0_8_centos ~]# cat 111.txt |awk'BEGIN{max=0}{if($1 > max) max=$1}END{print max}'
44
5.6、awk实现统计
[root@VM_172_116_centos wwwlogs]# cat   access_create.suo.im.log.bak|awk  '{ip[$1]++}END{for (p in ip) print p" "ip[p]}'
5.7、awk实现统计排序
[root@VM_172_116_centos wwwlogs]# cat   access_create.suo.im.log.bak|awk  '{ip[$1]++}END{for (p in ip) print p"" ip[p]}'|sort -k 2 -rn
此处讲一下sort命令
-k 位置 1,位置 2 根据关键字排序,在从第位置 1 开始,位置 2 结束
-r 倒序排序
-n 根据字符串数值比较
5.8、awk简单的统计排序
返回码
此处讲一下uniq
[root@VM_122_26_centos wwwlogs]# cataccess_u3v_cn.log|awk '{print $9}'|sort -n|uniq -c|sort -nr|awk '{print$2,$1}'|head -10
200 5789669
301 3274934
404 5809
400 4091
206 442
"-" 121
405 103
166 43
304 22
IP统计
[root@VM_122_26_centos wwwlogs]# cat  /home/wwwlogs/access_suo_im.log|awk '{print$1}'|sort -n|uniq -c|sort -nr|awk '{print $2,$1}'|head -50
111.230.208.12 41617
154.8.161.213 172
127.0.0.1 104
71.6.146.130 4
41.142.250.29 3
195.231.2.25 3
实战求一下nginx日志301状态占比?
6、Shell数组
Linux shell数组的创建与使用
4.1、创建数组
[root@VM_0_8_centos ~]# a=( 1 2 3 4 )
4.2、得到数组的长度
[root@VM_0_8_centos ~]# echo ${#a[@]}
4
4.3、读取数组的值
[root@VM_0_8_centos ~]# echo ${a[@]}
1 2 3 4
Shell数组下标是从0开始的
[root@VM_0_8_centos ~]# echo ${a[1]}
2
4.4、数组的赋值
[root@VM_0_8_centos ~]# a[1]=1000
[root@VM_0_8_centos ~]# echo ${a[1]}
1000
[root@VM_0_8_centos ~]# echo ${a[@]}
1 1000 3 4
[root@VM_0_8_centos ~]#
4.5、shell 数组的遍历
方法一
[root@VM_0_8_centos ~]# for((i=0;i<${#a[@]};i++)) do echo ${a}; done;
1
1000
3
4
方法二
[root@VM_0_8_centos ~]#  for i in ${a[@]};do echo $i ;done;
1
1000
3
4
[root@VM_0_8_centos ~]#
例子:循环处理多文件
[root@VM_0_8_centos opt]# r=( $(ls -l |awk  '{print $9}') )
[root@VM_0_8_centos opt]# echo ${#r[@]}
10
[root@VM_0_8_centos opt]# for i in${r[@]};do echo $i ;done;
libiconv-1.15
libiconv-1.15.tar.gz
mongodb-linux-x86_64-3.2.9.tgz
mysql-5.7.11-linux-glibc2.5-x86_64
mysql-5.7.11-linux-glibc2.5-x86_64.tar.gz
nginx-1.12.2
nginx-1.12.2.tar.gz
php-5.4.45
php-5.4.45.tar.gz
rh
[root@VM_0_8_centos opt]#
http://blog.chinaunix.net/uid-30810013-id-5766223.html
需求:JOB日志7天内保留,最近三个月内7天之外的压缩,超三个月的删除
目录:/app/---/log/biz
文件:jobid_yyyymmdd_序号.log
文件多少不确定
实现脚本如下:
说明:使用ls、awk、uniq命令分析出需求目录下有那些文件,在把这些文件放到数组中,然后进行循环处理。
#!/bin/sh
#author xj
#date 20170611
echo "###BEGIN###"
echo "begin time `date +%Y-%m-%d\ %H\:%M\:%S`"
cd /app/---/log/biz
zip_date=`date +"%Y%m%d" -d "-7 days"`
zip_date1=`date "+%Y%m%d" -d "-90 days"`
ar=( $(ls -l *${zip_date}*|awk  '{print $9}'|awk -F "_" '{print$1}'|uniq -c|awk '{print $2}') )
for (( i = 0; i < ${#ar[@]}; ++i ))
do
        tar -czvf ${ar}_${zip_date}.log.tar.gz ${ar}_${zip_date}_* --remove-files
        rm  -rf   ${ar}_${zip_date1}.log.tar.gz
done
7、Sort命令
功能:排序文本,默认对整列有效,对一行排序
-f 忽略字母大小写
-M 根据月份比较,比如 JAN、DEC
-h 根据易读的单位大小比较,比如 2K、1G
-g 按照常规数值排序
-n 根据字符串数值比较
-r 倒序排序
-k 位置 1,位置 2 根据关键字排序,在从第位置 1 开始,位置 2 结束
-t 指定分隔符
-u 去重重复行
-o 将结果写入文件
[root@izhp3bthgr0j2dfpah63xmz shell]# more a.txt |sort -gr
10
9
8
7
分隔后的字段排序:
[root@izhp3bthgr0j2dfpah63xmz shell]# cat /etc/passwd |sort -t : -k3 -n
大小单位排序:
[root@izhp3bthgr0j2dfpah63xmz shell]# du -sh * |sort -k 1 -h -r
对 file 文件的第二列正序排序,再次基础再对第三列倒序排序(多列排序):
sort -k 2 -n -k 3 -nr file
对两个文件同时排序:
# sort file1 file2
8、Uniq命令
功能:去除重复行,只会统计相邻的
|sort -n|uniq -c|sort -nr|head -10
常用选项:
-c 打印出现的次数
-d 只打印重复行
-u 只打印不重复行
-D 只打印重复行,并且把所有重复行打印出来
-f N 比较时跳过前 N 列
-i 忽略大小写
-s N 比较时跳过前 N 个字符
-w N 对每行第 N 个字符以后内容不做比较
去重复行:
[root@izhp3bthgr0j2dfpah63xmz shell]# sort aa|uniq
abc
abd
cde
xyz
打印每行重复次数:
[root@izhp3bthgr0j2dfpah63xmz shell]# sort aa|uniq -c
1 abc
1 abd
2 cde
2 xyz
[root@izhp3bthgr0j2dfpah63xmzshell]# more aa
abc
cde
xyz
cde
xyz
abd
[root@izhp3bthgr0j2dfpah63xmz shell]#
9、实战
实战求一下nginx日志301状态占比?
实战答案:
[root@VM_122_26_centos wwwlogs]# cat access_u3v_cn.log|awk '{print$9}'|sort -n|uniq -c|sort -nr|awk '{print $2,$1}'|awk'BEGIN{sum_count=0;suss_count=0}{sum_count+=$2;if($1==301){suss_count+=$2}}END{printf ("%.2f\n",suss_count/sum_count*100)}'
36.09
支付日志分析:
业务C
/data/tomcat-logs/logs-22080-pay-boss-trade/catalina/2019-02-28
[yunweihykj@ip-172-31-25-246 2019-02-28]$ cat  catalina.2019-02-28-14.out|grep 'respCode":'|head-2|awk -F"respCode" '{print "respCode"$2}'|awk -F'"''{print $3,$7}'

[yunweihykj@ip-172-31-25-246 2019-02-28]$ cat  catalina.2019-02-28-14.out|grep'respCode":'|awk -F"respCode" '{print"respCode"$2}'|awk -F'"' '{print $3,$7}'|sort|uniq -c|sort-nr|head -50
  27307 0000 请求成功
  16039 0000 上游返回:100-request success-平台处理为:成功
   4572 E6101 操作失败
   3222 0000 上游返回:100-成功-平台处理为:成功
   3063 0000 1
   2549 0000 上游返回:10-平台处理为:成功
   2449 0000
   1604 E5104 支付产品异常
   1571 0000 success
   1502 0000 上游返回:20-平台处理为:未知
   1502 : :
   1356 E5104 该支付产品无可用的通道商户支付方式
    921 0000 000000
    520 E6105 操作失败
     37 0000 handling-清算未明
     34 0000 SUCCESS
     33 0000 初始设值
     25 0000 00000-成功
     24 0000 上游接口返回成功
     22 : appId\
     22 7777 111111
     20 0000 成功
     20 0000 succ-交易完毕
     17 0010035\
     15 0000 处理中
     12 0000 交易成功
      6 E8003 支付流水已成功
      5 E6113 操作失败
      5 0000 查询商户余额结束,余额为:53089169.9270000
      5 0000 查询商户余额结束,余额为:2050082.45850000
      4 00\\\ 成功\\\
      3 E5101 操作失败
      3 0000 查询商户余额结束,余额为:53590769.9270000
      3 0000 查询商户余额结束,余额为:26482267.6000000
      3 0000 查询商户余额结束,余额为:1944356.05850000
      3 0000 交易失败
      2 E8001 操作失败
      2 E1004 订单号重复
      2 7777 操作失败
      2 0000 银行系统繁忙,客官莫急,请稍后再试或使用其他支付方式(1297)
      2 0000 查询商户余额结束,余额为:52757369.9270000
      2 0000 查询商户余额结束,余额为:52139469.9270000
      2 0000 查询商户余额结束,余额为:52016569.9270000
      2 0000 查询商户余额结束,余额为:51087869.9270000
      2 0000 查询商户余额结束,余额为:3684184.9180000
      2 0000 查询商户余额结束,余额为:27933367.6000000
      2 0000 查询商户余额结束,余额为:24015311.59850000
      2 0000 查询商户余额结束,余额为:17561667.6000000
      2 0000 查询商户余额结束,余额为:14294867.6000000
      2 0000 查询商户余额结束,余额为:109571045.4800000
阅读(3411) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~