提取包含D的A和(B或C)之间的线

我需要在A和(B或C)模式之间提取文本,其中包含D模式 .

例如,我有一个文件,需要在“proc sql”和(“quit”或“run”)之间提取所有内容,其中包含“index” .

proc sql
bla-bla-bla
index=10;
quit

proc sql
bla-bla-bla
quit;

proc sql
index=10;
run

需要的输出:

proc sql
bla-bla-bla
index=10;
quit

proc sql
index=10;
run

到现在我有这样的解决方案:

perl -0777 -lne 'print for grep /\bindex\b/i, /^proc sql.*?quit.*?\n/mgs' file

但它只提取“proc sql”和“quit”(不是“quit”或“run”),包含“index” . 我不知道如何添加OR操作 .

如果你可以提出替代awk / sed / grep解决方案 - 会很好 .

回答(2)

3 years ago

这会像你问的那样做 . 它累积到 $block 开始和结束模式之间的所有行 . 到达结束模式时,如果它包含 index ,则打印该块

use strict;
use warnings;

my $block;

while ( <DATA> ) {
  my $state = /^proc sql\b/ .. /^(?:quit|run)\b/;
  $block .= $_ if $state;
  if ( $state =~ /E/ ) {
    print $block, "\n" if $block =~ /^index=/m;
    $block = '';
  }
}

__DATA__
proc sql
bla-bla-bla
index=10;
quit

proc sql
bla-bla-bla
quit;

proc sql
index=10;
run

output

proc sql
bla-bla-bla
index=10;
quit

proc sql
index=10;
run

3 years ago

鉴于您的输入文件名为input.txt,这将在awk中解决它:

awk 'BEGIN {
    procDetected = 0;
    indexDetected = 0;
}

/proc/ {
    buffer = "";
    indexDetected = 0;
    procDetected = 1;
}

/index/ {
    indexDetected = 1;
}

{
    if (procDetected) {
        # Add the line to the buffer.
        buffer = buffer $0 "\n";
    }
}

/run/ || /quit/ {
    if (procDetected && indexDetected) {
        print buffer;
    }
    procDetected = 0;
    indexDetected = 0;
}' input.txt