Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Print Lines above and below string

by coding_new (Sexton)
on Aug 10, 2011 at 14:54 UTC ( [id://919672]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks,

I have a question reqarding printing x lines above and below a string found in a file. Currently I have the following code which identifies the string and prints the string and one line below. How would we modify this to print lets say 5 lines above and below the string?

I have searched but cant seem to find anything that does both. Most of what I found print either lines after or before when a string variable is found in the file. I am also not sure the way I have it is the best way to move forward with... Thanks for your input.

#!/usr/bin/perl use strict; $hits=0; $string_to_find="string"; $file = "filename"; open (LOGFILE, $file); while($line = <LOGFILE>) { if ($line =~ /$string_to_find/i) { $hits++; print "$line"; print scalar <LOGFILE>; } } close(LOGFILE);

Replies are listed 'Best First'.
Re: Print Lines above and below string
by jethro (Monsignor) on Aug 10, 2011 at 15:35 UTC

    Well, if you found examples that print lines before the hit and examples that print lines after the hit, you could just combine them

    Usually to print lines before a hit, you create a line storage where the previous 5 lines are stored. When you find the string print the previous lines from storage. To print 5 lines after a hit, just set a counter to 5 when you find it and print lines as long as the counter (that you decrement) is greater than 0. Both methods can be combined without any problems

    But the simple algorithms have one drawback: They will reprint lines if these are in the vicinity of two hits. This might be just what you want. If not, use the following method: Have a storage of 5 lines and a counter you set to 10. Always print from the storage, but compare the searchstring with the line you just read. If you get a hit set the counter to 10. Again print and decrement

    while ($line = <LOGFILE>) { push @storage, $line); if ($line =~ /$string_to_find/i) { $counter=10; } if (@counter-- and @storage>=5) { print shift @storage; } }

    Untested

Re: Print Lines above and below string
by thenaz (Beadle) on Aug 10, 2011 at 15:17 UTC

    So you want the context of the matched string. You will need to keep a rolling window of the last few lines you've seen. Actually, if your input isn't huge, just slurp up into an array, like so (untested):

    open LOGFILE, "<$file"; @lines = <LOGFILE>; for my $i (0..$#lines) { next unless $lines[$i] =~ /$string_to_find/i; my $a = $i - 5 < 0 ? 0 : $i - 5;; my $b = $i + 5 > $#lines ? $#lines : $i + 5; print $lines[$_i] for my $_i ($a..$b); }

      Thanks for the input. Few questions. My file sizes will be around 2.5 megs max. Not sure if that's a problem or not. Also once I ran the script you provided, I got an error on the last line

      Here is the error: syntax error at ./readlog5.pl line 12, near "$_i ("

      ++ for "Close!" ...but "untested" lets typos slip by:

      open (LOGFILE, "<$file") or die "Can't open $file"; my @lines = <LOGFILE>; my $lines; my $i; for $i(0..$#lines) { next unless $lines[$i] =~ /$string_to_find/i; my $a = $i - 5 < 0 ? 0 : $i - 5;; my $b = $i + 5 > $#lines ? $#lines : $i + 5; for $i($a..$b) { print $lines[$i]; } }
      what $#lines does? would anyone please me
Re: Print Lines above and below string
by Samy_rio (Vicar) on Aug 10, 2011 at 15:17 UTC

    this is one of the way. try this

    #!/usr/bin/env perl use strict; my $hits=0; my $string_to_find="string"; my $file = "filename"; open (LOGFILE, $file); my @cont = <LOGFILE>; close(LOGFILE); for(my $i = 0; $i <= $#cont; $i++) { my $line = $cont[$i]; if ($line =~ /$string_to_find/i) { my $st; ($i <= 5) ? ($st = 0) : ($st = $i - 5); my $ln = $i - 1; my $eln = $i + 1; my $en = $i + 5; ($en > $#cont) ? ($en = $#cont) : (); print @cont[$st..$ln]; print $line; print @cont[$eln..$en]; } }

    Regards,
    Velusamy R.


    eval"print uc\"\\c$_\""for split'','j)@,/6%@0%2,`e@3!-9v2)/@|6%,53!-9@2~j';

      That code provided me with what I needed. Thanks for your help.

Re: Print Lines above and below string
by Gulliver (Monk) on Aug 10, 2011 at 15:26 UTC
Re: Print Lines above and below string
by duyet (Friar) on Aug 10, 2011 at 15:14 UTC

    On the command line: grep -n5 "search_string" filename

    If you want to use it in your code

    my $result = `/usr/bin/grep -n5 "search_string" $file`; print $result;

      Thanks for the input, but when I tested out that code, it simply added 5 blank lines before and after my string.

        Sorry i first thought you wanted to print empty lines. Try the "grep" command, as in my updated post

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2024-04-24 20:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found