pythonnetwork-programmingcisco-iosciscoconfparse

Python - Read Specific Lines of Text


I'm trying to search files for specific text. Then print the line immediately prior to the line, and all subsequent lines that start with a specific character, particularly a 'space.'

Here's a sample of the file I'm trying to read:

interface vlan 22
 ip address 10.10.2.1 255.255.255.0
 ip helper-address 10.10.44.1
 ip helper-address 10.10.44.2
!
interface vlan 23
 ip address 10.10.23.1 255.255.255.0
 ip helper-address 10.10.44.1
 ip helper-address 10.10.44.2
!

When I see 'IP address' I want to print the line immediately prior, and then all the configuration items under that interface.

Currently, I'm reading from a directory of files and outputting specific information from the files. Here's the code:

for file in glob.glob('*.log'):
with open(file) as search:
    with open(queryoutput,"a") as foutput:
        for line in search:
            line = line.rstrip()
            if hostcheck in line:
                hostentry = line.split("hostname ")[1]
                foutput.write("Subnet information below is from " + hostentry + "\n")
            elif ipaddress in line:
                foutput.write("Local Device: " + hostentry + "\n")
                foutput.write("Remote " + line + "\n")

Not all network devices will state "interface" in the VLAN line, so that's why I don't want to search for that text, and there's not a guarantee an exclamation would be the last item, though it's highly probable. That's why I'm looking for a way to read the lines based on 'IP address' and spaces.

I'm still new to Python, and programming in general, but it looks like something like this might help. I'm just not fully understanding how that would work.

Any thoughts on how I can accomplish this? Also, I'm trying to use Python 3.x.


Solution

  • It would probably be easier to utilize a Cisco config-parsing library rather than start from first principles.

    For example, the ciscoconfparse module makes your problem as easy as the following, creating a dict with each interface mapped to a list of its configuration items. Searching for other object types would just be a matter of changing the argument to find_objects.

    Assuming we're dealing with a file named test-config:

    import pprint
    from ciscoconfparse import CiscoConfParse
    
    parse = CiscoConfParse("test-config", syntax="ios")
    
    pprint.pprint({
        obj.text: [child.text.strip() for child in obj.children]
        for obj in parse.find_objects(r"interface")
    })
    

    Result:

    {'interface vlan 22': ['ip address 10.10.2.1 255.255.255.0',
                           'ip helper-address 10.10.44.1',
                           'ip helper-address 10.10.44.2'],
     'interface vlan 23': ['ip address 10.10.23.1 255.255.255.0',
                           'ip helper-address 10.10.44.1',
                           'ip helper-address 10.10.44.2']}
    

    Edit: Regarding your additional question, it would probably be wise to read the documentation and tutorial for the module which contains, among other things, examples of how to search for entries with specific children. To achieve what you're asking for, you could modify the above to use the find_objects_w_child() function:

    pprint.pprint({
        obj.text: [child.text.strip() for child in obj.children]
        for obj in parse.find_objects_w_child(
            parentspec=r"^interf", childspec=r"ip .*address"
        )
    })