删除没有前面“已连接”的“已断开连接”的消息。信息

时间:2015-08-25 17:25:03

标签: bash perl awk sed

我有一个很长的日志文件,我试图摆脱包含foo disconnected的所有行,但没有包含foo has connected.的伴随行,这些行将在断开连接消息之前。关于这一点的棘手部分是该文件可以包含来自同一用户的多个断开连接消息,这些消息具有先前的连接消息,并且所有这些消息将在错误的断开连接消息之前。

例如,在此示例文件中,我想删除第4行,第6行和最后3行。

user1 has connected.
BigDaddy has connected.
user1 disconnected
foobar123 disconnected
user1 has connected.
noobmaster disconnected
user1 disconnected
BigDaddy disconnected
BigDaddy has connected.
user1 disconnected
user1 disconnected
user1 disconnected

4 个答案:

答案 0 :(得分:1)

保留已连接用户的哈希值

该程序期望输入日志文件的路径作为命令行上的参数

use strict;
use warnings;

my %connected;

while ( <> ) {

    my ($user, $action) = split ' ', $_, 2;

    if ( $action =~ /disconnected/i ) {
        next unless $connected{$user};
        $connected{$user} = 0;
    }
    elsif ( $action =~ /connected/i ) {
        $connected{$user} = 1;
    }

    print;
}

输出

user1 has connected.
BigDaddy has connected.
user1 disconnected
user1 has connected.
noobmaster disconnected
BigDaddy has connected.
user1 disconnected


在Perl中编写简洁的难以理解的代码并非不可能。这是the awk solution from chepner的转换。它具有与上面相同的输出,但请注意我对他的解决方案的评论中的疑虑

perl -n -e'
    ($u) = /(\S+)/;
    $arr[$u] = 1 if /has conn/;
    print if $arr[$u];
    $arr[$uarr[$1]] = 0 if /disconn/
' tmp.txt

答案 1 :(得分:0)

awk中,使用数组来跟踪哪些用户有活动连接。

awk '/has conn/ { arr[$1]=1; }
     arr[$1] {print}
     /disconn/ {arr[$1]=0}' tmp.txt

请注意,我们会检查arr[$1] 之前的值在断开的行上禁用它,以便仍然打印第一行连续行。

答案 2 :(得分:0)

my @lines = <DATA>;
my %status = ();
foreach my $line (@lines) {
        my ($user) = $line =~ /([A-Za-z0-9]+)\s+/;
        #User has connected and not defined or disconnected
        if($line =~ /has connected/ && !$status{$user}){
                $status{$user} = 1;
                print $line;
        }
        # Connected user disconnected.
        elsif($line =~ /disconnected/ && $status{$user}){
                $status{$user} = 0;
                print $line;
        }
}

答案 3 :(得分:-1)

使用

open FILE, "<disconnect.txt" or die $!;
my @lines = <FILE>;
close FILE or die $!;
my @connectedusers = ();

foreach $line(@lines) {
    # if connected, then push user name to array
    if($line =~ /(\w+) has connected/) {
        push(@connectedusers, $1);
        print $line;
    # if disconnected, then check whether user name is in array
    } elsif ($line =~ /(\w+) disconnected/) {
        my $idx = 0;
        foreach(@connectedusers) {
            if(/$1/) {
                # remove user name from array
                splice(@connectedusers, $idx, 1);
                print $line;
            }
            $idx++;
        }
    }
}