打印范围从某个模式的最后一次出现到另一个模式的第一次出现

打印范围从某个模式的最后一次出现到另一个模式的第一次出现

早上好,这和问题非常相似Grep 从最后一次出现的模式到另一个模式(几个月前),同时添加更多细节。

我正在尝试为具有多个重复模式的文件编写 UNIX 脚本,后跟我要查找的模式。但是,我没有“tac”或“tail -r”(使用 UNIX 模拟器 MKS Toolkit),并且希望返回 Pattern2 之前最后一次出现的 Pattern1,然后是 Pattern1 和 Pattern2 之间的数据,然后是 Pattern2还。本例中的模式为“条件 1”和“条件 2”:

输出:

...
Condition 1: A
data1
Condition 1: B
data2
Condition 2: C
data3
Condition 1: D
data4
Condition 1: E
data5
Condition 2: F
...

我想编写一个 awk (或 sed,但认为 awk 将是正确的工具)脚本来返回:

Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F

我认为这是下面一行的某种形式,但我无法正确理解语法:

awk '/Condition 1/ {acc = $0;} /,/Condition 2/ {print ?}' output.out

使用“/,/”似乎是我遇到困难的地方。想知道是否有人有任何建议,将不胜感激。非常感谢与此问题相关的任何帮助和时间。

答案1

尝试:

$ awk 'f{a=a"\n"$0} /Condition 1/{a=$0; f=1} f && /Condition 2/{print a; f=0}' output.out 
Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F

怎么运行的

  • f{a=a"\n"$0}

    如果变量f为真(非零),则将当前行附加到变量的末尾a

  • /Condition 1/{a=$0; f=1}

    如果当前行包含Condition 1,则设置s为当前行并将变量设置f为 1。

  • f && /Condition 2/{print a; f=0}

    如果f为 true 并且当前行包含Condition 2,则打印变量a并设置f回零。

答案2

当您希望在文本处理中进行反向寻址时,请使用ex

它是POSIX 指定vi,它是(以及vi它的直接前身)的可编写脚本的形式——非常灵活。

printf '%s\n' 'g/Condition 2/?Condition 1?,.p' | ex output.out

这意味着:

对于与模式“条件 2”匹配的每一行(g全局),向后搜索“条件 1”的前一个实例,并p打印从该行到当前行 ( .) 的所有行(即带有“条件 2”的行)它)。

提供的输入的输出与您所描述的完全相同。

答案3

sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x' infile

尽管这假设任何匹配的行PATTERN_2前面至少有一个匹配的行PATTERN_1。对于更一般的情况,添加另一个条件来PATTERN_1在打印之前测试模式空间中是否存在:

sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x;/PATTERN_1/!d' infile

答案4

这是 Perl 的一个邪恶之处:

perl -0777 -ne '
    my $c1 = qr/Condition 1/;
    my $c2 = qr/Condition 2/;
    print for map {s/$c2.*?\n\K.*//s; $_}
              grep {/$c2/}
              split /(?=$c1)/ms;
' output.out

它:

  • 读取整个文件(使用-0777-n选项),
  • 在出现条件 1 的位置将其拆分 ( split),
  • 过滤掉条件 2 未出现的段落 ( grep),
  • 然后从每个感兴趣的段落中删除条件 2 行 ( map) 之后的所有行。

相关内容