Languages and Scripting

find a line and print lines before and after w/o duplication

 
SOLVED
Go to solution
Scott Lindstrom_2
Regular Advisor

find a line and print lines before and after w/o duplication

This may be more than can reasonably be expected to be done without a major coding effort, but I'll throw it out as a challenge. I want to search a file for a string then print a few lines on either side. But the string in question appears a few times in a row, so I don't really want to print 5 lines on either side of the first occurence, then 5 lines on either side of the second occurence, etc since this will be a lot of the same output. Here is an example of the file:

/oracle/FS1: stat: No such file or directory
fuser: could not find or access file /oracle/FS1.
mount: /oracle/FS1: No such file or directory
/oracle/FS1: stat: No such file or directory
fuser: could not find or access file /oracle/FS1.
mount: /oracle/FS1: No such file or directory
ERROR: Function freeup_busy_mountpoint_and_mount_fs
ERROR: Failed to mount /dev/vg27/lvol1 to /oracle/FS1
ERROR: Function check_and_mount
ERROR: Failed to mount /dev/vg27/lvol1
Jul 9 08:51:09 - Node "myhostname": Deactivating volume group /dev/vg27
Deactivated volume group in Exclusive Mode.
Volume group "/dev/vg27" has been successfully changed.
Jul 9 08:51:09 - Node "myhostname": Deactivating volume group /dev/vg03
Deactivated volume group in Exclusive Mode.
Volume group "/dev/vg03" has been successfully changed.
Jul 9 08:51:09 - Node "myhostname": Deactivating volume group /dev/vg04

I want to search for "ERROR" then print the lines around it (so I can more easily find the real error).

Does anyone have any suggestions they'd like to throw out?
3 REPLIES 3
James R. Ferguson
Acclaimed Contributor
Solution

Re: find a line and print lines before and after w/o duplication

Scott:

This would print 3-lines on either side of the pattern 'ERROR:" if it starts at the beginning of a line:

# cat ./matchit
#!/usr/bin/perl
use strict;
use warnings;
my $pattern = qr/^ERROR:/; #...or whatever...
my $lines_around = 3; #...as wanted...
my ( $i, @lines );
while (<>) {
chomp;
shift @lines if @lines > $lines_around;
push @lines, $_;
if (m{$pattern}) {
for my $line (@lines) {
print $line, "\n";
}
$i = $lines_around;
@lines = ();
}
else {
$i-- > 0 and print "$_\n";
}
}
1;

...run as:

# ./matchit file

Regards!

...JRF...
Scott Lindstrom_2
Regular Advisor

Re: find a line and print lines before and after w/o duplication

James - that works great! Thanks!
Dennis Handly
Acclaimed Contributor

Re: find a line and print lines before and after w/o duplication

GNU grep has a -B n and -A n option. It seems to use advanced AI technology to do what you want about matches close by:
$ /usr/local/bin/grep -n -B1 -A1 find foo
3-33333333333333
4:find it
5:find it
6-666666666666