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

时间:2015-07-01 03:53:46

标签: awk sed pattern-matching range

第一次来电...长期读者。

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

.
.
.
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

3 个答案:

答案 0 :(得分:1)

使用sed:

使用GNU sed:

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

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

如何运作

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

    这是用于立即读取整个文件的sed习语。如果文件很大,请使用不同的解决方案,例如下面的awk解决方案。

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

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

使用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设置为true(1)。

  • f{print}

    如果标记f为真,则打印行

  • /exit/ && last {exit;}

    如果此行包含exit且上一行也包含exit,那么我们就完成了,我们告诉awk exit

  • {last=0}

    将last设置为false(0)。

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

    准备下一行。如果标记f为真且此行包含exit,则将last设置为true(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解决方案相同。

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

这可能适合你(GNU sed):

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

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