欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

awk处理实记

程序员文章站 2023-01-28 17:14:28
经grep日志后得到的数据格式如下: 希望将一条原始数据处理后,生成若干条以下格式的数据: 由于很久没有用过awk了,先复习了一遍语法做了些小实验才正式开始。经过整理后的思考路径如下: 整个路径看起来是挺简单的,实际上用了我好几个小时才写出了完整可用的awk。特此记录下遇到的问题及得到教训。 最后, ......

经grep日志后得到的数据格式如下:

}
 .
[debug][2019-05-20 00:00:00] senddatastyled:{
   "cmd" : 0001,
   "innings" : "6189269620_0007",
   "players" : [
      {
         "al_board" : 1,
         "al_win" : 1,
         "alter_exp" : 0,
         "alter_money" : 10,
         "uid" : 34329592
      },
      {
         "al_board" : 1,
         "al_win" : 0,
         "alter_exp" : 0,
         "alter_money" : -26,
         "uid" : 13416009
      },
      {
         "al_board" : 1,
         "al_win" : 1,
         "alter_exp" : 0,
         "alter_money" : 16,
         "uid" : 41165640
      }
   ],
   "roomid" : "6189269620",
   "vid" : 1205
}

希望将一条原始数据处理后,生成若干条以下格式的数据:

time al_win alter_money uid roomid

 

由于很久没有用过awk了,先复习了一遍语法做了些小实验才正式开始。经过整理后的思考路径如下:

  1. 确定分隔符。 原本是想用空格,“[”, “]”,三个符号做分隔的,实验后发现由于打印格式的问题,很多字段前面都有很多个空格,这样不太好数需要的字段编号。所以最后分隔符定为中括号,双引号,冒号,逗号。
  2. 确定所需字段分隔后的编号。 根据分隔符数一下,然后通过命令行验证一下就可以了。这个还是很容易且快的。
  3. 思考如何组织并输出数据。 基本想法是除了要重复用到的time和roomid保存一下,其它字段是拿到后就直接打印,读取uid之后,打印uid及roomid就进行换行。有点困难的是roomid的读取,因为awk是按行顺序处理的,一个uid打印一行数据的话就等不到读后面的roomid了。幸好发现在数据innings里实际上隐含着roomid,拿到innings后用“_”截取前面一段就可以了。
  4. 实操。

 

整个路径看起来是挺简单的,实际上用了我好几个小时才写出了完整可用的awk。特此记录下遇到的问题及得到教训。

  1. 尽量用awk脚本写,不要在命令行直接写。 也是因为只稍微复习了下语法就开始的原因,不知道可直接写在文件里调用,在命令行写极易出错,不易阅读,而且修改起来相当痛苦。
  2. 自定义变量的生命周期。 不说太深,只说现今用到的。awk我们日常用到的自定义变量基本都是全局变量,直接使用就可以了。只是要注意下自己的程序应当在什么时候对变量进行初始化。如果只初始化一次,就在begin里写;如果需要在具体的行里多次初始化,在begin不用初始化也可以直接用。
  3. 变量的使用。 也是由于复习不到位的问题,没有注意到使用变量时不需要使用$,比如要打印nf变量,直接print nf即可。因为这个小问题,走了不少弯路,深刻的教训。
  4. printf 的随意性。 如果没有定义具体的打印格式,printf后接空格,再接要打印的变量名或字段就可以了,用逗号或空格分隔都可以。要打印的所有变量可以用小括号包起来,也可以不包起来。不得不说,真的是强!
  5. 定义分隔符在命令行和脚本里的不同。 以上文确定的分隔符为例,在命令行应该写作 -f '[][":,]' , 在脚本里则应该在begin里写成 fs="[][\":,]"; 。

 

最后,贴上写完的脚本:

source.awk

begin {
fs="[][\":,]";
}

{
if($4~/2019-/) a=$4":"$5":"$6;
else if($2~/innings/) split($5, b, "_");
else if($2~/al_win/) printf a $4;
else if($2~/alter_money/) printf $4;
else if($2~/uid/) printf "%s %s\n", $4, b[1];
}

直接使用 awk -f source.awk data.log > res.txt 即可。

 

另附参考的awk基础知识: