#!/usr/bin/perl -w #extract lines in a given date range from an xchat logfile #is a bit too hardcoded to be translated to other clients (gaim, etc) #sorry! Future update will see this more modular. use Getopt::Std; use strict; #extractDate(\%hash, $line) #extract the contents of the date in line and put it in a hash #(hash is keyed by month, day, hour, minute, second) sub extractDate; #buildRegex($line) #build a regex from an input string of the form MM HH MM:SS:DD and return it sub buildRegex; my %args; my $buffer; #regexes for quick and easy pattern matching my $startregex; my $endregex; #start and end date hashes for more complex range matching my %startdate; my %enddate; # additional regex to check for in lines of output my $addlRegex = ".*"; #Yeah this is a bit hackish. Whaddya want from me? This is, like, my second perl script. my %monthvals = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11, jan => 0, feb => 1, mar => 2, apr => 3, may => 4, jun => 5, jul => 6, aug => 7, sep => 8, oct => 9, nov => 10, dec => 11, ); my $help; $help = < inputfile -h : this help -s : Starting date -e : Ending date -r : Further restrict the search to lines matching this regex (search, not replace) inputfile defaults to stdin if no file provided Dates are expected in "Month Day Hour:Minute:Second" format. Months are abbreviated to 3 letters, non-case sensitive. You must provide AT LEAST one regex. (If one is missing, then it is assumed that both -s and -e are equal.) To search for all lines on the 13th of May: logger -s "May 13 *:*:*" xchatlogfile To search for all lines between the 13th of May and the 20th of June: logger -s "May 13 *:*:*" -e "Jun 20 *:*:*" xchatlogfile To search for all lines written between 5 and 10 pm in the entire log: logger -s "* * 17:*:*" -e "* * 22:*:*" xchatlogfile As above, but only match lines containing "somenick" logger -s "* * 17:*:*" -e "* * 22:*:*" -r somenick xchatlogfile EOT getopt ( "hxs:e:f:r:", \%args ); # there's quite a bit of redundancy in the argument checking. Sue me. if ( $args{h} ) { print $help; exit; } if ( $args{r} ) { $addlRegex = $args{r}; } if ( $args{s} ) { $startregex = buildRegex($args{s}); extractDate(\%startdate, $args{s}); } if ( $args{e} ) { $endregex = buildRegex($args{e}); extractDate(\%enddate, $args{e}); } if ( !$args{e} && !$args{s} ) { print $help; exit; } elsif ( !$args{e} || !$args{s} ) { if ( $args{s} ) { $endregex = $startregex; extractDate(\%enddate, $args{s}); } elsif ( $args{e} ) { $startregex = $endregex; extractDate(\%startdate, $args{e}); } } while ( <> ) { my $toPrint; if ( $_ =~ m/^\*\*\*\*/i || $_ =~ m/^\s*\n/i ) { # this is a xchat log status line (effectively a comment for our purpose) next; } if ( $_ =~ m/$startregex/i || $_ =~ m/$endregex/i ) { $toPrint = $_; } else { # not lucky enough for an exact match ... check the date my %linedate; extractDate(\%linedate, $_); # check the dates to see if the date in the line is between startdate # and end date if ( !($enddate{month} eq "*") && $monthvals{$linedate{month}} <= $monthvals{$enddate{month}} && $monthvals{$linedate{month}} >= $monthvals{$startdate{month}} ) { if ( !($enddate{day} eq "*") && $linedate{day} <= $enddate{day} && $linedate{day} >= $startdate{day} ) { if ( !($enddate{hour} eq "*") && $linedate{hour} <= $enddate{hour} && $linedate{hour} >= $startdate{hour} ) { if (!($enddate{minute} eq "*") && $linedate{minute} <= $enddate{minute} && $linedate{minute} >= $startdate{minute} ) { if (!($enddate{second} eq "*") && $linedate{second} <= $enddate{second} && $linedate{second} >= $enddate{second} ) { $toPrint = $_; } } } } } } if ( $toPrint && ($toPrint =~ m/$addlRegex/) ) { print $toPrint; } } sub buildRegex { my $orig = shift; # make sure to not muck up the original my $regex = $orig; $regex =~ s/\s/\\s/g; $regex =~ s/\*/\.\*/g; return $regex; } sub extractDate { my $finalDate = shift; #expects a reference to a hash my $buff = shift; #expects a line of text from the logfile #expects buff in the form MM DD HH:MM:SS my @date = split " ", $buff; my @time = split ":", $buff; $time[0] =~ s/$date[0]\s$date[1]\s//; $finalDate->{month} = $date[0]; $finalDate->{day} = $date[1]; $finalDate->{hour} = $time[0]; $finalDate->{minute} = $time[1]; my @splitline = split " ", $time[2]; $finalDate->{second} = $splitline[0]; }