IT技术博客大学习 共学习 共进步

awk 实例之二维数组

小小子,simaopig 2010-07-15 08:40:44 浏览 5,922 次
由于 AWK 不支持二维数组,有时候使用起来还真不是那么得心应手。

这不,本次应用又遇到了难题,要是按照PHP的想法,仍然是用二维数组搞定,两层foreach一循环啥都完事了。可是不行啊,一个文件几十万行,用PHP去分析那不死的要多惨有多惨?

先来看一下日志结构,和原来一样,每行一条记录,用{SPR}分隔字段,第二个字段为游戏名,第四个字段为用户ID,现在要统计每个游戏的用户ID,且要消重,于是,困难来了。

以下是引用片段:
Jul 13 23:59:58  [info] {SPR}poker{SPR}20100713235958{SPR}39487249{SPR}S1{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}40321910{SPR}S5{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}45937395{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46047210{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46100689{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}mcsd{SPR}20100713235958{SPR}46144879{SPR}S22{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46193512{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46249154{SPR}S9{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46311452{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46361704{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46401796{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}46412612{SPR}S10{SPR}
Jul 13 23:59:58  [info] {SPR}dfh{SPR}20100713235958{SPR}46414008{SPR}7{SPR}
Jul 13 23:59:58  [info] {SPR}dandan{SPR}20100713235958{SPR}6428766{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}mcsd{SPR}20100713235959{SPR}26810901{SPR}S1{SPR}
Jul 13 23:59:59  [info] {SPR}wulin{SPR}20100713235959{SPR}28006063{SPR}hero10.wan.360.cn{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}29498036{SPR}S2{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}30401399{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}plsm{SPR}20100713235959{SPR}33290378{SPR}S3{SPR}
Jul 13 23:59:59  [info] {SPR}wulin{SPR}20100713235959{SPR}35130674{SPR}hero14.wan.360.cn{SPR}
Jul 13 23:59:59  [info] {SPR}mcsd{SPR}20100713235959{SPR}35990716{SPR}S22{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}39135264{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}39263733{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}45902989{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}46051567{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}46237264{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}46241464{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}46320919{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}46337146{SPR}S10{SPR}
Jul 13 23:59:59  [info] {SPR}dandan{SPR}20100713235959{SPR}46411556{SPR}S10{SPR}
 

绞尽脑汁,加上同事帮助,一共弄了两种实现方式,大家简单看一下

以下是引用片段:
#将字段按{SPR}分隔
BEGIN{FS="{SPR}";OFS="\t"}
{
        name=$2;
        #用三止运算符,将gamearr数组里KEY为游戏名,结果为换行符加上用户ID
        gamearr[name]=gamearr[name](gamearr[name]?"\n":"")$4;
}
END{
        #循环每个游戏
        for (name in gamearr) 
        {
            #各个游戏对应的文件名
            filename = name".log";
            print gamearr[name] > filename;
        }
}

上面的是同事帮忙想的,下面是自己写的,见笑

以下是代码片段:
#将字段按{SPR}分隔
BEGIN{FS="{SPR}";OFS="\t";}
{
    #arrgame数组的KEY是游戏
    arrgame[$2]++;
    #gameqid数组的KEY是游戏,用户ID
    gameqid[$2,$4]++;
}
END{
    #循环每个游戏
    for(name in arrgame) 
    {
        filename = name".log";
        for(qid in gameqid)
        {
            #将游戏名与用户ID分隔开,存放在qidarr数组中
            split(qid,qidarr,SUBSEP); 
            if(name == qidarr[1]){
                print qidarr[2] > filename;
            }
        }
    }
}

解决问题的方法有很多,重要的是敢想,敢试。看来有时候人的大脑不运动的话,生起锈来比肌肉萎缩还吓人。

建议继续学习

  1. Linux命令行里的“瑞士军刀” (阅读 11,442)
  2. AWK 简明教程 (阅读 9,142)
  3. awk命令,实现文件的合并与拆分 (阅读 6,961)
  4. AWK介绍 (阅读 6,580)
  5. 更快的IP库查找方法以及AWK中的二分查找 (阅读 6,400)
  6. 操作大文本,awk vs vim (阅读 4,960)
  7. SED命令行脚本快速参考,AWK命令行脚本快速参考,perl命令行脚本快速参考 (阅读 4,743)
  8. 从shell中向awk传递变量实例 (阅读 4,480)
  9. bash shell - sed及awk文本捕获及替换 (阅读 4,202)
  10. bash shell - sed, awk文本捕获及替换 (阅读 4,163)