如何让 sed 删除非缩进行下方的缩进文本块,该行也包含特定的正则表达式,但不超出该范围?

如何让 sed 删除非缩进行下方的缩进文本块,该行也包含特定的正则表达式,但不超出该范围?

我几乎一整天都在与 GPT、sed 文档和正则表达式作斗争。我试图解析包含思科前缀列表配置的文件,并打印出与给定正则表达式列表名称不匹配的列表,并忽略该列表的内容或同一列表名称下和缩进的内容。

例如,我的文件如下所示(网络混淆):

ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispC_out_deny
    seq 10 permit 23.1.24.3/24
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispE_out_deny
    seq 10 permit 9.2.3.4/24
    seq 20 permit 4.4.4.1/24
ip prefix-list ispF_out_deny
    seq 10 permit 2.2.3.4/24
    seq 20 permit 28.2.3.1/24
ip prefix-list ispG_out_deny
    seq 10 permit 4.2.3.4/24
ip prefix-list ispH_in_pref-150
ip prefix-list ispI_out_deny
    seq 10 permit 3.2.3.4/24

我想要的是:

ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispH_in_pref-150

我不断得到的是这样的输出(加上 sed 命令):

:~$ sed -e '/deny/{:a;N;/\n.*seq.*/!ba;d}' file
ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
    seq 20 permit 4.4.4.1/24
    seq 20 permit 28.2.3.1/24
ip prefix-list ispH_in_pref-150

请注意它如何从完全不同的列表中获取其他 2 个“seq 20”行。

对于 GPT,它给出了这样的例子:

Line 1
Pattern Line
Line 2
This is a line below Line 2
Another line below Line 2
Pattern Line
Line 3

结果如下:

:~$ sed -e '/Line 2/{:a;N;/\nPattern.*/!ba;d}' input_file
Line 1
Pattern Line
Line 2
Line 3

我已经能够重现这一点,但不能使用 ACL 文件。

我可以发誓有一种方法可以通过保留缓冲区来做到这一点,从而为 sed 提供一些上下文,但我无法重新定位该帖子,所以我也不知道是否还运行了其他命令。 sed 是否会因为网络符号中的“/”而感到困惑?有一个更好的方法吗?

答案1

awk:

$ awk '/deny/ { deny=1; next }
       /^ip/  { deny=0; print; next }
       !deny' < data
ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispH_in_pref-150

答案2

使用任何 awk:

$ awk '/^ip/{f=/deny/} !f' file
ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispH_in_pref-150

答案3

您面临的挑战是因为 Cisco 前缀列表本质上是分层的,并且单独使用正则表达式sed可能会变得相当复杂。它更适合单行模式匹配和替换。为了达到您想要的结果,您可能需要更强大的文本处理工具,例如awkperl。这是一个使用以下解决方案awk

awk '
  /^ip prefix-list/ {  # If the line starts with "ip prefix-list"
    list_name = $3   # Set list_name to the third field
    match(list_name, /^.*\//)  # Check if list_name contains a slash
    if (RSTART) {  # If it does, it's a main list, print it
      print
      in_main_list = 1
    } else {  # Otherwise, it's a sub-list, ignore it
      in_main_list = 0
    }
  }
  /^ / && in_main_list {  # If the line starts with a space (sub-list) and in_main_list is true
    next  # Skip this line
  }
  in_main_list {  # If we are inside a main list, print the line
    print
  }
' file

该脚本的作用如下awk

  1. 当它遇到以“ip prefix-list”开头的行时,它会检查列表名称是否包含斜杠(“/”)。如果是,则将其视为主列表,脚本将打印它并将标志 ( in_main_list) 设置为 true。

  2. 如果该行以空格开头并且in_main_list为 true,则它会跳过该行(忽略子列表条目)。

  3. 如果in_main_list为 true,则打印该行。

该脚本应该为您提供所需的输出,过滤掉子列表条目。

相关内容