#!/usr/bin/perl # The Missing Textutils, Ondrej Bojar, obo@cuni.cz # http://www.cuni.cz/~obo/textutils # # 'picklog' reads stdin to extract useful snippets of information into a nice # table. # # Usage: picklog cmd1 cmd2 ... < input # # Allowed commands: # RE ... same as find RE # find RE ... scan till the line where RE is found # pick RE(what) ... pick something from the current line # or the first next matching line # next ... advance to the next line of input # nl ... add a newline to the output # let:VARNAME RE(what) ... for RE and store it in internal variable # VARNAME # watch:VARNAME RE(what) ... simultaneously search for RE and store it # in internal variable VARNAME, whenever found # count:VARNAME RE ... like watch but store just the number of lines # that matched RE so far # print:VARNAME ... print internal variable VARNAME # # A 'nl' is always added at the end of the commands. # # The commands are looped, as long as there are some input lines to read. # # The variables are useful for finding the last something before something else # or for swapping columns in the output. # # $Id: picklog,v 1.6 2009-05-28 23:15:49 bojar Exp $ # # Ondrej Bojar use strict; my @cmds = @ARGV; @ARGV = (); push @cmds, "nl"; binmode(STDIN, ":utf8"); binmode(STDOUT, ":utf8"); binmode(STDERR, ":utf8"); my $watches; # maps target varnames to regular expressions for watching my $counts; # maps target varnames to regular expressions for counting my $vars; my $re = undef; my $todo = "find"; my @output = (); while (<>) { foreach my $watch (keys %$watches) { if (/$watches->{$watch}/) { $vars->{$watch} = $1; } } foreach my $count (keys %$counts) { if (/$counts->{$count}/) { $vars->{$count} ++; } } NEXT_ON_THE_SAME_LINE: if (!defined $re) { $re = shift @cmds; push @cmds, $re; if ($re eq "next") { $re = undef; # ask for a new command next; # advance the line } if ($re eq "nl") { print join("\t", @output)."\n"; @output = (); $re = undef; # ask for a new command goto NEXT_ON_THE_SAME_LINE; } if ($re =~ /^watch:(.*)$/o) { $re = shift @cmds; push @cmds, $re; $watches->{$1} = $re; # set the watch $re = undef; # ask for a new command goto NEXT_ON_THE_SAME_LINE; } if ($re =~ /^count:(.*)$/o) { $re = shift @cmds; push @cmds, $re; $counts->{$1} = $re; # set the watch $re = undef; # ask for a new command goto NEXT_ON_THE_SAME_LINE; } if ($re =~ /^print:(.*)$/o) { push @output, $vars->{$1}; # emit the current value $re = undef; # ask for a new command goto NEXT_ON_THE_SAME_LINE; } if ($re =~ /^(find|pick|let:.*)$/o) { $todo = $re; $re = shift @cmds; push @cmds, $re; # this is the re to search for goto NEXT_ON_THE_SAME_LINE; } } if (/$re/) { # found our re! my $found = $1; # store the picked part if ($todo eq "pick") { push @output, $found; # put it on the output list $re = undef; # ask for a new command $todo = "find"; goto NEXT_ON_THE_SAME_LINE; } elsif ($todo =~ /^let:(.*)$/o) { $vars->{$1} = $found; # assign the variable $re = undef; # ask for a new command $todo = "find"; goto NEXT_ON_THE_SAME_LINE; } else { # just found, do the next command; $re = undef; goto NEXT_ON_THE_SAME_LINE; } } } # print final output, if any print join("\t", @output)."\n" if 0 == scalar @output;