AWK,在多个日志文件中计算机器名称的频率

时间:2018-07-02 07:28:59

标签: bash shell logging awk

我的日志文件至少有100G。 日志文件目录结构如下:

drwxrwxr-x 2 griyn griyn 4096 Jul  2 14:33 lcdc-0615-00.log
drwxrwxr-x 2 griyn griyn 4096 Jun 29 14:22 lcdc-0615-01.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-02.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-03.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-04.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-05.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-06.log

在每个目录中,

[griyn@cp01-vm-griyn test_data]$ cd lcdc-0615-00.log/
[griyn@cp01-vm-griyn lcdc-0615-00.log]$ ll
total 361216
-rw-rw-r-- 1 griyn griyn 184936785 Jun 28 21:19 yq01-spi-mx0.yq01
-rw-rw-r-- 1 griyn griyn 184936680 Jun 28 21:20 yq01-spi-mx22.yq01

在此处记录文件内容

  1 peer_addr[yq01-spi-mx38:29129]
  2 peer_addr[yq01-spi-mx38:29129]
  3 peer_addr[yq01-ps-beehive-agent3677:29082]
  4 peer_addr[yq01-spi-mx38:29129]
  5 peer_addr[yq01-spi-mx38:29129]
  6 peer_addr[yq01-spi-mx38:29129]
  7 peer_addr[yq01-ps-beehive-agent3677:29082]
  8 peer_addr[yq01-spi-mx38:29129]
  9 peer_addr[yq01-spi-mx38:29129]
 10 peer_addr[yq01-ps-beehive-agent3677:29082]
 11 peer_addr[yq01-spi-mx38:29129]
 12 peer_addr[yq01-ps-beehive-agent3677:29082]
 13 peer_addr[yq01-spi-mx38:29129]
 14 peer_addr[yq01-ps-beehive-agent3677:29082]
 15 peer_addr[yq01-spi-mx38:29129]
 16 peer_addr[yq01-spi-mx38:29129]
 17 peer_addr[yq01-ps-beehive-agent3677:29082]
 18 peer_addr[yq01-spi-mx38:29129]
 19 peer_addr[yq01-spi-mx38:29129]
 20 peer_addr[yq01-ps-beehive-agent3677:29082]
 21 peer_addr[yq01-spi-mx38:29129]
 22 peer_addr[yq01-ps-beehive-agent3677:29082]
 23 peer_addr[yq01-spi-mx38:29129]

我想通过shell脚本计算多个日志文件中机器名称的频率。 我这样使用AWK:

awk -F'[]:[]' '/peer_addr/{map[$2]+=1} END{for(key in map) {sum+=map[key];printf("%-15s %s\n", key, map[key]);} print "sum:",sum}' ${log_file_dir}/${log_path} >> ./conclusion/sum.log &

显然,我们需要一个地图结构来保存和更新结果。然后我有一个问题,就是AWK中的地图结构仅用于自已AWK。我无法将结果汇总到多个日志文件中。

我的临时解决方案是,使用AWK将每个日志文件的结果输出到一个文件,然后在该文件旁边再次使用AWK求和。

您有更有效的方法吗?

1 个答案:

答案 0 :(得分:2)

如果文件数量很多,比允许的最大参数列表大得多,则可以通过以下方式使用Awk:

  1. 使用您要处理的所有文件创建文件。

    $ find <logroot> -type f -iname '*.yq01' > <logroot>/logfiles.txt
    
  2. 使用awk自己创建ARGV列表:

    $ awk -F'[]:[]' '(NR==FNR){ARGV[ARGC++]=$0; next}
                     /peer_addr/{map[$2]++}
                     END{ for(key in map) {
                             sum+=map[key];
                             printf("%-15s %s\n", key, map[key]);
                          }
                          print "sum:",sum }
                    ' <logroot>/logfiles.txt
    
  

ARGC ARGV数组中的元素数。

     

ARGV:一组命令行参数,不包括选项和程序参数,从零到ARGC-1编号。    ARGV中的参数可以修改或添加; ARGC可以更改。在每个输入文件结束时,awk会将ARGV的下一个非null元素视为ARGC-1的当前值(包括该值),下一个输入文件的名称。因此,将ARGV的元素设置为null意味着不应将其视为输入文件。名称'-'表示标准输入。如果参数与赋值操作数的格式匹配,则应将该参数视为赋值,而不是文件参数。

     

来源:awk POSIX standard

并行处理:

如果您想进行一些并行处理,您可能会对GNU parallel感兴趣:

$ cat <logroot>/logfiles.txt              \
   | parallel --jobs 4 ./process_files.sh \
   | awk '{map[$1]+=$2}
          END{ for(key in map) {
                  sum+=map[key];
                  printf("%-15s %s\n", key, map[key]);
               }
               print "sum:",sum
             }'

process_files.sh

#!/usr/bin/env bash
awk -F'[]:[]' '(NR==FNR){ARGV[ARGC++]=$0; next}
               /peer_addr/{map[$2]++}
               END{ for(key in map) {
                      sum+=map[key];
                      printf("%-15s %s\n", key, map[key]);
                    }}' "$@"