打印文本文件的统​​计信息

打印文本文件的统​​计信息

我有一个如下所示的文本文件(events.dat)(注意仅显示摘录)

RepID12 01/01/2010 20:56:00 S10
RepID12 01/01/2010 20:56:00 S03
RepID20 01/01/2010 20:56:00 S17
RepID33 01/01/2010 20:56:00 S02
RepID33 01/01/2010 20:56:00 S18
RepID38 01/01/2010 20:56:00 S11
RepID39 01/01/2010 20:56:00 S20
RepID26 02/01/2010 01:39:00 S20
RepID29 02/01/2010 01:39:00 S16
RepID29 02/01/2010 01:39:00 S03
RepID22 02/01/2010 01:39:09 S01
RepID26 02/01/2010 01:39:09 S02
RepID40 02/01/2010 01:39:18 S02
RepID38 02/01/2010 01:39:09 S05
RepID31 02/01/2010 01:39:09 S06
RepID31 02/01/2010 01:39:09 S08
RepID09 02/01/2010 01:39:09 S09
RepID23 02/01/2010 01:39:18 S09
RepID19 02/01/2010 01:40:09 S09
RepID21 02/01/2010 01:40:18 S09
RepID28 02/01/2010 01:40:27 S09
RepID43 02/01/2010 01:40:09 S14

等等,涵盖总时间跨度为 48 小时的事件。我只想打印每分钟发现超过 60 个事件时的行。

例如,使用此命令,我可以计算 1 分钟内有多少个事件:

grep "02/01/2010 01:39" events.dat | wc -l

这将返回 60(例如),这应该是每分钟的最大事件数。

我怎样才能做同样的事情,但检查整个 48 小时内的每一分钟并仅打印出发现超过 60 个事件/分钟的行?提前谢谢

答案1

理想情况下,您只想尝试仅处理该文件一次,并将尽可能少的内容存储在内存中。在 中awk,你可以这样做:

awk -v n=60 '
  {
    t = $2 substr($3, 1, 5);
    if (t == last_t) {
      if (++lines > n)
        print
      else
        if (lines == n)
          print saved $0
        else
          saved = saved $0 RS
    } else {
      saved = $0 RS
      lines = 1
      last_t = t
    }
  }' < your-file

这种方法的一些优点:

  • 这是面向流处理的。输入一到来就立即处理,并尽快发出输出(一旦看到第 60 行)。这使得对实时输出进行后处理成为可能(就像在 a 上一样tail -fn +1 log_file)。
  • 它只运行一个命令 ( awk) 的一次调用,因此将尽可能高效。相反的极端是循环运行多个命令。 shell 脚本中成本最高的事情通常是分叉和执行命令。优化意味着尽可能减少这种情况。
  • 我们在内存中最多只存储 60 行,因此内存使用量将受到限制(假设行本身的大小受到限制)。
  • awk代码可以变得非常清晰且不言自明。现在,如果尺寸很重要,您也可以将其缩短并放在一行上,例如

    awk '{t=$2substr($3,1,5);if(t==l){if(++i>n)print;else if(i==n)print s$0;else s=s$0RS}else{s=$0RS;i=1;l=t}}' n=60 file
    

答案2

这不是最有效的解决方案,但您可以首先计算每分钟的事件数,然后当计数 >= 60 时,为这些分钟中的每一分钟 grep 文件。

sort -k 2,3 your_log_file \
| uniq -c -s 8 -w 16 \
| while read count _ date time _; do
    [ "$count" -ge 60 ] && grep -F " $date ${time%:*}" your_log_file
done

笔记:

  • 在上面的基本示例中,我首先按时间顺序对文件进行排序
  • 如果这是您唯一感兴趣的信息,前两行将为您提供每分钟的事件数。

如果您的文件充满了事件,您很可能最终会grep对其执行大量操作。更好的解决方案是按顺序读取日志文件,并记住最后一分钟的行。当您到达下一分钟时,如果这些行的数量大于 60,则打印这些行。有关此类解决方案,请参阅 Stéphane 的答案。

答案3

通过这样的方法,您可以隔离可用的分钟数:

root@debian:# awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq
01/01/2010 20:56
02/01/2010 01:39
02/01/2010 01:40
02/01/2010 20:56

然后您可以使用这些值分配一个数组

修改后的代码:

readarray -t stamps < <(awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq)
for stamp in "${stamps[@]}";do
ev=$(grep "$stamp" b.txt |wc -l)
echo "In $stamp found $ev events "
#if [ "$ev" -gt 60 ]; then
# do the stuff
#fi
done

输出:

In 01/01/2010 20:56 found 7 events 
In 02/01/2010 01:39 found 11 events 
In 02/01/2010 01:40 found 4 events 
In 02/01/2010 20:56 found 7 events 

答案4

awk '{ print $2 " " $3 }' < input \
| cut -c1-16                      \
| sort                            \
| uniq -c                         \
| awk '{ if ($1 > 60) print $2 }'

即获取日期和时间字段,去掉秒数,对结果进行排序(注意:如果您的日期采用 ISO 格式,效果会更好),找到每个唯一日期/时间组合的计数,然后使用计数 > 打印它们60

相关内容