I want to use grep with regex to match part of a line, then proceed to print that line and the next 2 lines. But I don’t want to print any match where the second line after the match includes another regex pattern.
Example text:
If the line was there is a loom in the gloom
would you want that line printed?
Just trying to understand if you're just
other than as part of gloom
if you really do want to exclude lines
even when loom appears on it's own elsewhere on the line
Searching for the pattern, gloom; using grep -Pn -A2 '^.*\b(gloom)\b.*$' *
will print
If the line was there is a loom in the gloom
would you want that line printed?
Just trying to understand if you're just
..and
other than as part of gloom
if you really do want to exclude lines
even when loom appears on it's own elsewhere on the line
But I don’t want to print the second group that includes the word, elsewhere, on its third line. Using Perl-regex.
CodePudding user response:
Here is an example in Perl:
use v5.20.0; # signatures requires perl >= 5.20
use feature qw(say);
use strict;
use warnings;
use experimental qw(signatures);
{
my $lines = read_file('file.txt');
for my $i (0..$#$lines) {
my $line = $lines->[$i];
if ($line =~/\b(gloom)\b/) {
if (!match_second_pattern($lines, $i)) {
print_block($lines, $i);
}
}
}
}
sub print_block($lines, $i) {
my $N = $#$lines;
for my $j (0..2) {
last if $i $j > $N;
print $lines->[$i $j];
}
}
sub match_second_pattern($lines, $i) {
my $N = $#$lines;
return 0 if ($i 2) > $N;
return $lines->[$i 2] =~ /elsewhere/;
}
sub read_file( $fn ) {
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
my @lines = <$fh>;
close $fh;
return \@lines;
}
CodePudding user response:
This type of problem is usually solved using negative lookahead. Unfortunately, I don't believe you can get command line grep
to lookahead across line boundaries so this would take a Perl program to accomplish:
#!/usr/bin/perl
use strict;
my $s = "If the line was there is a loom in the gloom
would you want that line printed?
Just trying to understand if you're just
other than as part of gloom
if you really do want to exclude lines
even when loom appears on it's own elsewhere on the line";
while ($s =~ /^.*?\bgloom\b(?!.*\n.*\n.*?\belsewhere\b).*\n.*\n.*\n?/mg) {
print "$&";
}
If you want to have the input specified on the input line as coming in from stdin or a file, then:
#!/usr/bin/perl -w
use strict;
my $s = '';
# read from stdin or the file specified on the command line:
while (<>) {
$s .= $_ ;
}
while ($s =~ /^.*?\bgloom\b(?!.*\n.*\n.*?\belsewhere\b).*\n.*\n.*\n?/mg) {
print "$&";
}