仅汇总唯一条目的日志文件

2 投票
3 回答
1097 浏览
提问于 2025-04-17 15:23

我在工作中已经用这个脚本好几年了,主要是用来总结日志文件。

 #!/usr/bin/perl

 $logf = '/var/log/messages.log';

 @logf=( `cat $logf` );
 foreach $line ( @logf ) {
      $line=~s/\d+/#/g;
      $count{$line}++;
 }

 @alpha=sort @logf;
 $prev = 'null';
 @uniq = grep($_ ne $prev && ($prev = $_), @alpha);
 foreach $line (@uniq) {
      print "$count{$line}: ";
      print "$line";
 }

我一直想用Python重写它,但有些部分我不是很理解,比如:

 @alpha=sort @logf;
 $prev = 'null';
 @uniq = grep($_ ne $prev && ($prev = $_), @alpha);

有没有人知道有没有Python的模块可以让我不用重写这个?我找了很久都没找到类似的东西。谢谢大家!

3 个回答

1

我得说,我经常看到有人在用Python做一些事情,而这些事情在Shell或Bash里只需要一行代码就能完成。

我不在乎被点踩,因为大家应该明白,如果在Shell里能用一行代码搞定的事情,就没必要用20行Python去做。

< my_file.txt | sort | uniq > uniq_my_file.txt
3

正如变量的名字所暗示的,

@alpha=sort @logf;
$prev = 'null';
@uniq = grep($_ ne $prev && ($prev = $_), @alpha);

这个过程是在找出独特的元素(也就是去掉重复的行),同时忽略行中的数字,因为这些数字之前已经被替换成了#。这三行可以写成

@uniq = sort keys(%count);

或者甚至可以写成

@uniq = keys(%count);

在Perl中还有另一种写这个程序的方法:

my $log_qfn = '/var/log/messages.log';
open(my $fh, '<', $log_qfn)
   or die("Can't open $log_qfn: $!\n");

my %counts;
while (<$fh>) {
   s/\d+/#/g;
   ++$counts{$_};
}

#for (sort keys(%counts)) {
for (keys(%counts)) {
   print "$counts{$_}: $_";
}

这样写应该更容易转换成Python。

2
 @alpha=sort @logf;
 $prev = 'null';
 @uniq = grep($_ ne $prev && ($prev = $_), @alpha);

这相当于

uniq = sorted(set(logf))

如果logf是一系列行的话。

不过,由于你是在统计行的出现频率,你可以使用collections.Counter来同时统计行数和收集唯一的行(作为键),这样就不需要再计算uniq了:

count = collections.Counter()
for line in f:
    count[line] += 1

import sys
import re
import collections

logf = '/var/log/messages.log'
count = collections.Counter()
write = sys.stdout.write

with open(logf, 'r') as f:
    for line in f:
        line = re.sub(r'\d+','#',line)
        count[line] += 1

for line in sorted(count):
     write("{c}: {l}".format(c = count[line], l = line))

撰写回答