1

I've been fighting with GPT, the sed documentation, and regex for almost my entire day. I'm trying to parse through files that contain cisco prefix-list configurations and print out the lists that don't match a given regexp list name, and ignore the contents of that list or what is under the same list name and indented.

For example, my files look like this (networks obfuscated):

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

What I want is:

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

What I keep getting is output like this (plus the sed command):

:~$ 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

Notice how it's taking the other 2 "seq 20" lines from a different list entirely.

With GPT, it gave this as an example:

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

Gave this as a result:

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

And I've been able to reproduce this, but not with the ACL files.

I could've sworn there was a way to do this with hold buffers that gave sed some semblance of context but I cannot relocate the post so I also don't know if other commands were ran with it. Is sed getting confused because of the "/" in the network notation? Is there a better way to do this?

3 Answers 3

0

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
0

Using any 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
-2

Your challenge arises because the Cisco prefix-lists are hierarchical in nature, and using regular expressions with sed alone can become quite complex. It's better suited for single-line pattern matching and replacements. To achieve your desired result, you may need a more powerful text processing tool, such as awk or perl. Here's a solution using 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

Here's what this awk script does:

  1. When it encounters a line starting with "ip prefix-list," it checks if the list name contains a slash ("/"). If it does, it's considered a main list, and the script prints it and sets a flag (in_main_list) to true.

  2. If the line starts with a space and in_main_list is true, it skips the line (ignores sub-list entries).

  3. If in_main_list is true, it prints the line.

This script should give you the desired output, filtering out sub-list entries.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .