sed - 范围匹配 - 范围的一侧是多行模式

sed - range match - one side of the range is a multiline pattern

第一次来电...很长时间reader。

这是我正在使用的输入示例。

.
.
.
exit
exit
set vsys "dr-site"
set vsys-id 2
set vrouter "dr-site-vr"
unset auto-route-export
exit
set service "service1"
set service "service2"
set zone id 101 "Trust1"
set zone id 201 "Untrust1"
set zone id 301 "DMZ1"
set interface "ethernet3/1.3"
set interface "ethernet3/1.4"
set interface "ethernet3/1.6"
set route 0.0.0.0/0
set address "Untrust1"
set address "Trust1"
set address "DMZ1"
set group address "Untrust1"
set group address "Trust1"
set group address "DMZ1"
set group service
set policy id 100
exit
set policy id 200
exit
set policy id 300
exit
set policy id 400
exit
exit
set vsys "datacenter"
set vsys-id 1
set vrouter "datacenter-vr"
unset auto-route-export
exit
set service "service1"
set service "service2"
set zone id 100 "Trust"
set zone id 200 "Untrust"
set zone id 300 "DMZ"
set interface "ethernet3/1.5"
set interface "ethernet3/1.2"
set interface "ethernet3/1.1"
set route 0.0.0.0/0
set address "Untrust"
set address "Trust"
set address "DMZ"
set group address "Untrust"
set group address "Trust"
set group address "DMZ"
set group service
set policy id 100
exit
set policy id 200
exit
set policy id 300
exit
set policy id 400
exit
exit
set vsys "other"
.
.
.

我需要从 set vsys "datacenter" 开始我的范围(例如)并在我看到 (2) 个连续的 exit 时停止。

通常,我只是:

gsed -n '/set vsys "datacenter"/,/exit/p; file

但我需要模式 #2 来捕捉 (2) 连续退出:

gsed -n '/set vsys "datacenter"/,/exit\nexit/p; file

因此我的范围匹配具有范围 #2 的多行模式。

我试过使用 sed N 命令,但我没有做正确的事。我还将使用此 sed 命令根据需要解析出 vsys 部分,这些部分始终以 (2) 连续 exit.

结尾

根据要求,预期输出应如下所示:

set vsys "datacenter"
set vsys-id 1
set vrouter "datacenter-vr"
unset auto-route-export
exit
set service "service1"
set service "service2"
set zone id 100 "Trust"
set zone id 200 "Untrust"
set zone id 300 "DMZ"
set interface "ethernet3/1.5"
set interface "ethernet3/1.2"
set interface "ethernet3/1.1"
set route 0.0.0.0/0
set address "Untrust"
set address "Trust"
set address "DMZ"
set group address "Untrust"
set group address "Trust"
set group address "DMZ"
set group service
set policy id 100
exit
set policy id 200
exit
set policy id 300
exit
set policy id 400
exit
exit

使用 sed:

使用 GNU sed:

sed -r 'H;1h;$!d;x;s/.*(set vsys "datacenter".*exit\nexit).*//' file

对于 BSD sed,尝试将 -r 替换为 -E

工作原理

  • H;1h;$!d;x;

    这是一次读取整个文件的 sed 习惯用法。如果文件很大,请使用不同的解决方案,例如下面的 awk 解决方案。

  • s/.*(set vsys "datacenter".*exit\nexit).*//

    这提取了我们想要的部分。

使用 awk

awk '/set vsys "datacenter"/{f=1;} f{print;} /exit/ && last {exit;} {last=0;} f && /exit/{last=1;}' file

工作原理

  • /set vsys "datacenter"/{f=1;}

    当我们看到起始行时,将标志 f 设置为真 (1)。

  • f{print}

    如果标志 f 为真打印行

  • /exit/ && last {exit;}

    如果这一行包含exit并且前一行也包含exit,那么我们就完成了,我们告诉awk到exit.

  • {last=0}

    将 last 设置为 false (0)。

  • f && /exit/{last=1}

    这为下一行做准备。如果标志 f 为真且此行包含 exit,则将 last 设置为真 (1)。

使用python3

#!/usr/bin/python3
f = False
last = False
with open('file', 'r') as fhandle:
    for line in fhandle:
        if 'set vsys "datacenter"' in line:
            f = True
        if f:
            print(line, end="")
        if last and 'exit' in line:
            break
        last = False
        if f and 'exit' in line:
            last = True

此处的逻辑与 awk 解决方案基本相同。

未经测试,因为您没有提供预期的输出,但您需要这样的东西:

awk '
/set vsys "datacenter"/{ f=1; rec=prev="" }
f {
    rec=rec [=10=] ORS
    if ( /exit/ && (prev==[=10=]) ) {
        printf "%s", rec
        f=0
    }
    prev = [=10=]
}
' file

这可能适合您 (GNU sed):

sed '/set vsys "datacenter"/!d;:a;N;/exit\s*\nexit\s*$/!ba' file

如果某行不包含所需的字符串,请将其删除。如果是,则追加以下行并检查双 exit 条件,如果未找到,则继续追加行直到满足条件。打印出模式 space.

中的行