Beginner Lab
CLI Output Parsing
Objective
Parse raw, unstructured CLI text into a list of dictionaries, then compute a summary of which interfaces are healthy and which aren't.
Builds on Python for Network Engineers.
Prerequisites
- Comfortable with Python strings, lists, and dictionaries (Lists & Dictionaries for Network Data)
- Comfortable with for loops and conditions (Conditions & Loops)
Scenario
The problem
A colleague pastes you the output of show ip interface brief from a switch and asks: "which interfaces actually need attention?" Right now the only way to answer that is to read the text by eye, line by line. Every script this curriculum builds from here on assumes device state already looks like a list of dictionaries -- but real CLI output never starts that way. This lab is the missing first step: turning raw text into that structured shape yourself.
Every lesson since "Your First Network Automation" has worked with data that was already structured for you. This lab doesn't -- you start from plain text, exactly as a real terminal session would hand it to you.
Starter data
Interface IP-Address OK? Method Status Protocol
GigabitEthernet0/0 10.10.10.1 YES NVRAM up up
GigabitEthernet0/1 10.10.10.5 YES NVRAM up down
GigabitEthernet0/2 unassigned YES NVRAM administratively down down
Vlan1 unassigned YES NVRAM administratively down downThis is fixed sample text, written for this lab -- not captured from any real device. The address space (10.10.10.x) is documentation-only, matching this curriculum's convention throughout.
Task
Write a function parse_interface_brief(raw_output) that takes the raw text above and returns a list of dictionaries, one per interface, each with these keys: interface, ip_address, status, protocol.
The tricky part: Status can be one or two words ("up" vs. "administratively down"), but Protocol is always exactly the last column. Work backward from the end of each line rather than assuming a fixed column count.
Then write summarize(interfaces), returning:
total: how many interfaces were parsedup_up: how many are fully up (status == "up"andprotocol == "up")mismatched: interface names wherestatusis"up"butprotocolisn't -- a real, common signature (physical layer fine, line protocol not negotiating)administratively_down: interface names that are shut down
RAW_OUTPUT = """Interface IP-Address OK? Method Status Protocol
GigabitEthernet0/0 10.10.10.1 YES NVRAM up up
GigabitEthernet0/1 10.10.10.5 YES NVRAM up down
GigabitEthernet0/2 unassigned YES NVRAM administratively down down
Vlan1 unassigned YES NVRAM administratively down down
"""
def parse_interface_brief(raw_output):
# Your code here. Split into lines, skip the header, split() each
# data row, and pull interface / ip_address / status / protocol out
# of the resulting fields.
...
def summarize(interfaces):
# Your code here.
...
if __name__ == "__main__":
parsed = parse_interface_brief(RAW_OUTPUT)
for iface in parsed:
print(iface)
print(summarize(parsed))Copy this into a local .py file and run it with plain python3 -- no external packages needed for this lab.
Expected output
{'interface': 'GigabitEthernet0/0', 'ip_address': '10.10.10.1', 'status': 'up', 'protocol': 'up'}
{'interface': 'GigabitEthernet0/1', 'ip_address': '10.10.10.5', 'status': 'up', 'protocol': 'down'}
{'interface': 'GigabitEthernet0/2', 'ip_address': 'unassigned', 'status': 'administratively down', 'protocol': 'down'}
{'interface': 'Vlan1', 'ip_address': 'unassigned', 'status': 'administratively down', 'protocol': 'down'}
{'total': 4, 'up_up': 1, 'mismatched': ['GigabitEthernet0/1'], 'administratively_down': ['GigabitEthernet0/2', 'Vlan1']}Real, verified output from a working solution to this exact starter code.
Self-check only -- nothing here is submitted or graded. Compare against your own output manually.
Solution
Try the task yourself first -- the full solution and explanation stay hidden until you click above.
Key takeaways
- Real CLI output starts as plain text, not a ready-made dict -- this lab practiced the step every later lesson skips past.
- str.split() plus positional indexing is enough for one known column layout; it's brittle, which is exactly why NAPALM/TextFSM-based normalization (taught later) exists.
- Working from both ends of a line inward handles a variable-width middle column without regex.
- All sample data here is fixed, offline text -- no device, connection, or credential of any kind was involved.
Related lessons
Done with this lesson?