grep regex匹配并打印更多行,但如果额外的行包含不同的模式,则忽略打印(或不匹配)



我想使用grep与regex匹配一行的一部分,然后继续打印该行和接下来的2行。但是我不想打印任何匹配在match之后的第二行包含另一个正则表达式模式。

示例文本:

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

搜索模式,阴郁;使用grep -Pn -A2 '^.*b(gloom)b.*$' *将打印

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
但是我不想打印第二组包含单词,在第三行。使用Perl-regex。

下面是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;
}

这类问题通常使用负向前看来解决。不幸的是,我不相信您可以让命令行grep跨行向前看,所以这将需要一个Perl程序来完成:

#!/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 =~ /^.*?bgloomb(?!.*n.*n.*?belsewhereb).*n.*n.*n?/mg) {
print "$&";
}

参见Perl Demo

参见Regex Demo

如果您希望在输入行指定来自stdin或文件的输入,则:

#!/usr/bin/perl -w
use strict;
my $s = '';
# read from stdin or the file specified on the command line:
while (<>) {
$s .= $_ ;
}
while ($s =~ /^.*?bgloomb(?!.*n.*n.*?belsewhereb).*n.*n.*n?/mg) {
print "$&";
}

您可以使用像

这样的GNUgrep
grep -oPzn '(?m)^.*?bgloomb(?!(?:.*R){2}.*?belsewhereb)(?:.*R){2}.*R?' file > outputfile

细节:

  • -o-输出匹配的文本,而不仅仅是发生匹配的行
  • z-现在,换行符是呜呜声,可以与regex
  • 匹配
  • (?m)^-行起始
  • .*?-除换行符外的任何零个或多个字符,尽可能少
  • bgloomb-全字gloom
  • (?!(?:.*R){2}.*?belsewhereb)gloom单词下面的第二行,不应该有elsewhere作为一个完整的单词
  • (?:.*R){2}-当前行的剩余部分,下一行和换行
  • .*R?-整行(第二行),可选换行(序列)。

查看在线演示:

#!/bin/bash
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"
grep -oPzn '(?m)^.*?bgloomb(?!(?:.*R){2}.*?belsewhereb)(?:.*R){2}.*R?' <<< "$s"