Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

need to extract top and bottom lines...

by Anonymous Monk
on Dec 14, 2004 at 19:49 UTC ( [id://414831]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to write a script that searches for the string ERROR in a log and print that line as well as the line above it to a CSV file. However, I am not sure how to get the line directly above the error line to print. Here is my code.
open (DIFFR, "/tmp/log.diff"); while (<DIFFR>) { $line=$_; #read first line chomp($line); if ($line =~ /ERROR/) { print CSVFILE "$line,"; }
The reason is that the ERROR line has pertinent info the line directly above it in the log file. Here is some sample data:
2004.12.01 20:00:49.307 Agent.AgentLOG saveToSYS_AGENT_RUN_LOG() ourhost(10.10.52.36) ERROR: ********* memo == *** End Execution

Replies are listed 'Best First'.
Re: need to extract top and bottom lines...
by Eimi Metamorphoumai (Deacon) on Dec 14, 2004 at 19:55 UTC
    Just keep a copy of each line, ready to print if the next one matches.
    use strict; use warnings; my $last_line=''; open (DIFFR, "/tmp/log.diff") or die "Can't open /tmp/log.diff: $!"; while (<DIFFR>) { chomp; if (/\bERROR\b/) { print CSVFILE $last_line; print CSVFILE "$line,"; } $last_line = $_; }
Re: need to extract top and bottom lines...
by saberworks (Curate) on Dec 14, 2004 at 21:30 UTC
    Sometimes it's pointless to use perl. If you have grep on your system consider using grep -B 1 ERROR log.diff.
      saberworks,
      Sometimes it's pointless to use perl.

      This is very true. There are plenty of command line utilities and variants that were designed for a very specific task that they do very well. Not an exhaustive list, but I am quite fond of:

      • cut
      • sort
      • uniq
      • grep
      • tail
      • head

      The last one is what I wanted to comment on. Not all greps support -B. It is a GNU invention. HPUX and Solaris (at least up to 8), for instance, do not ship with it. When I have to work to make one of these do what I want, I tend to revert back to Perl.

      Cheers - L~R

        I encounter this problem very frequently on Solaris. My solution is just to install the GNU tools and modify my $PATH accordingly. http://www.sunfreeware.com is a real beaut. If you have a Solaris box without sufficient privileges to do this or an agreeable sysadmin, you have my sympathy.
        I also use "sed" quite often and "awk" is nice if you want to grab columns out of a file. Just last week someone told me the letters in awk stand for the names of the developers (Aho, Weinberger, Kernighan).

        I actually have command lines about two lines long that I use to work out things like for example which IP addresses are connected to my machine's SMTP port sorted by number of connections. I just haven't gotten around to writting a script or setting up a shell alias to do it yet.

        I played with a perl shell once but it didn't feel right (ie I wasn't used to it yet, years of BASH have me in their grasp). Also the control characters (^U, ^A, ^E, etc) didn't work on the main server I use at work (but did on my desktop). I don't remember the shell name but I think it supported commands something like " ls -1 | s/aaa/bbb/g " and more.
        In that case I'd use awk to solve this problem.
Re: need to extract top and bottom lines...
by zejames (Hermit) on Dec 14, 2004 at 19:56 UTC
    How about
    my $previous; open F, "< /tmp/log.diff" or die "Unable to open file : $!\n"; while (<F>) { chomp; if (m/ERROR/) { print CSVFILE, "$previous\n$_\n"; } $previous = $_; }

    --
    zejames
Re: need to extract top and bottom lines...
by kvale (Monsignor) on Dec 14, 2004 at 19:56 UTC
    The idea here is to keep a context, by storing the previous line:
    open (DIFFR, "/tmp/log.diff") or die "Could not open ;/tmp/log.diff\n" +; my $prev = <DIFFR>; while (my $curr = <DIFFR>) { print "$prev$curr" if $curr =~ /ERROR/; $prev = $curr; }

    -Mark

      how about a one-liner? perl -ne "print qq($last\n$_) if /ERROR/; $last=$_" logfile>csvfile
        You can add a little logic to the one-liner to cope with more general cases where some ERROR messages don't span two lines (assuming messages all start with a timestamp).

        perl -ne 'sub BEGIN {$l="";}$l=$_, next unless /ERROR/;print /^[^12]/ +? "$l$_" : $_;$l=$_;' some.log

        Not Y3K compliant.

        JohnGG

        Note: something is eating the square brackets around the character class ^12 for some reason. Code tags don't help.

Re: need to extract top and bottom lines...
by kutsu (Priest) on Dec 14, 2004 at 19:59 UTC

    There might be an easier way but you could do this:

    open (DIFFR, "/tmp/log.diff"); while (<DIFFR>) { $line=$_; chomp($line); if ($line =~ /ERROR/) { print CSVFILE "$oldline\n"; #look below if stat. print CSVFILE "$line,"; } $oldline = $line; #sets a variable with the last line }

    "Cogito cogito ergo cogito sum - I think that I think, therefore I think that I am." Ambrose Bierce

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://414831]
Approved by kvale
Front-paged by Mutant
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-04-25 14:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found