NetAuto Academy

Beginner Lab

CLI Output Parsing

Beginner20 min

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)
Local/offline only. Sample text only -- no device, no connection, no credentials of any kind.

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

raw_output.txt — safe sample data, not a real device
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

This 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 parsed
  • up_up: how many are fully up (status == "up" and protocol == "up")
  • mismatched: interface names where status is "up" but protocol isn't -- a real, common signature (physical layer fine, line protocol not negotiating)
  • administratively_down: interface names that are shut down
starter.py
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.

Hints

Expected output

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.

Validation checklist

Self-check only -- nothing here is submitted or graded. Compare against your own output manually.

Solution

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?