Free tech learning for everyone, from basics to pro

Python for NetworkingProgramming and Application SecurityIntermediate

Parsing device output and logs with Python regular expressions

In short: Regular expressions describe text patterns. With the re module you can capture fields such as interface names and IP addresses from show commands and logs, then store them as dictionaries. Use raw strings, named groups and tested sample data, and reach for TextFSM or Genie templates for common commands.

Why parse text at all

Many devices still answer in human-friendly text. To act on that output, a script needs it as data: which interfaces are down, which neighbours exist, how many errors a port has. A regular expression (regex) is a compact pattern language for finding and capturing parts of text. Python’s built-in re module provides it.

Parsing device outputCollectshow commandtextMatchre.finditerCapturenamed groupsStructurelist of dictsUsereport orcheck
Figure 1. Regular expressions turn raw command output into structured data you can test and report on.

Core regex tokens

Regex building blocks\d+one or more digits\S+non-space run\s+whitespace^ and $start and end( )capture group(?P<name>)named group
Figure 2. A handful of tokens covers most network parsing jobs.

Always write patterns as raw strings (r"...") so Python does not treat backslashes as its own escape codes. Use re.search() to find the first match anywhere, re.match() to match only at the start, and re.finditer() to loop over every match. Named groups, written (?P<name>...), let you read results by name with m["name"].

import re

output = """Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet0/0     192.168.10.1    YES manual up                    up
GigabitEthernet0/1     unassigned      YES unset  administratively down down
Loopback0              10.255.0.1      YES manual up                    up"""

pattern = re.compile(
    r"^(?P<intf>\S+)\s+(?P<ip>\S+)\s+\w+\s+\w+\s+"
    r"(?P<status>up|down|administratively down)\s+(?P<proto>up|down)$",
    re.MULTILINE,
)

interfaces = [m.groupdict() for m in pattern.finditer(output)]
for i in interfaces:
    print(i["intf"], i["ip"], i["status"])

down = [i["intf"] for i in interfaces if i["proto"] != "up"]
print("Down:", down)

re.MULTILINE makes ^ and $ match at the start and end of every line, not only the whole string. The header line does not match, so it is skipped automatically.

Parsing logs

Syslog messages have a fairly regular shape, which makes them good regex targets. This example counts interface state changes per interface from a log file.

import re
from collections import Counter

log_re = re.compile(
    r"%LINEPROTO-5-UPDOWN: Line protocol on Interface (?P<intf>\S+), "
    r"changed state to (?P<state>up|down)"
)

flaps = Counter()
with open("syslog.txt", encoding="utf-8") as f:
    for line in f:
        m = log_re.search(line)
        if m:
            flaps[m["intf"]] += 1

for intf, count in flaps.most_common(5):
    print(intf, count)

Tip: build patterns against real sample output saved in a file, and test them before trusting them. An online tester is fine for learning, but never paste confidential logs into third-party websites.

Pitfalls and better alternatives

  • Greedy matching: .* grabs as much as possible. Prefer specific tokens such as \S+, or the lazy form .*?.
  • Escape special characters: a literal dot in an address is \.. Better still, capture \S+ and check it with the ipaddress module.
  • Fragile patterns: output changes between software versions. Fail loudly when nothing matches instead of silently reporting "no problems".
  • Slow patterns: nested repeats such as (a+)+ can take exponential time on some input (ReDoS, regular expression denial of service). Keep patterns simple, especially on input from untrusted sources.
ApproachBest for
Your own regexLogs, one-off or unusual output
TextFSM templates (for example the ntc-templates collection)Common show commands across many vendors
Cisco Genie/pyATS parsersDetailed Cisco output
Structured APIs (NETCONF, RESTCONF, JSON output)Avoiding screen scraping altogether

Netmiko can call TextFSM for you with use_textfsm=True. When a device offers structured output, use it: parsing text should be a fallback, not the plan.

Practice

Why should regex patterns be written as raw strings in Python?
So backslashes such as \d and \s reach the regex engine unchanged instead of being treated as Python string escapes.
What does re.MULTILINE change?
It makes ^ and $ match at the start and end of each line, which is what you want when parsing multi-line command output.
Your parser finds zero down interfaces after a software upgrade. What should you suspect?
The output format may have changed so the pattern no longer matches. Scripts should report when nothing matches rather than assume all is well.

Key takeaways

  • Use the re module with raw strings and compiled patterns.
  • Named groups and groupdict() turn matches into dictionaries.
  • re.MULTILINE is needed for line-based device output.
  • Prefer specific tokens over greedy .* and keep patterns simple to avoid ReDoS.
  • Use TextFSM, Genie or structured APIs where they exist.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.