NTC-Templates and TextFSM: Parsing CLI Output - 夜莺博客

NTC-Templates and TextFSM: Parsing CLI Output

Regex against CLI output works until the first device upgrades and changes a column. TextFSM replaces ad-hoc regex with a template: named capture groups define the fields, a state machine defines which lines matter, and the result is a list of dictionaries that can go straight into a report, a database, or a compliance check. NTC-Templates is the community collection of those templates for hundreds of show commands across vendors. This guide covers using them, writing one from scratch, and wiring parsing into automation.

Install and parse an existing command

pip install textfsm ntc-templates

python3 -c "
from ntc_templates.parse import parse_output
raw = open('show_vlan.txt').read()
rows = parse_output(platform='cisco_ios', command='show vlan', data=raw)
import json; print(json.dumps(rows, indent=2))
"
[
  {"vlan_id": "10", "name": "Users",  "status": "active", "interfaces": ["Gi1/0/1", "Gi1/0/2"]},
  {"vlan_id": "20", "name": "Voice",  "status": "active", "interfaces": ["Gi1/0/3"]}
]

The platform string must match a Netmiko platform name (cisco_ios, cisco_xr, juniper_junos, arista_eos, huawei_vrp). A wrong platform produces an empty list rather than an error — check for empty results before assuming the device returned nothing.

Netmiko integration

from netmiko import ConnectHandler

device = {
    "device_type": "cisco_ios",
    "host": "10.10.10.11",
    "username": "automation",
    "password": "<pw>",
    "secret": "<enable>",
}

with ConnectHandler(**device) as conn:
    structured = conn.send_command("show ip interface brief", use_textfsm=True)
    for row in structured:
        if row["status"] == "up" and row["proto"] == "up":
            print(row["interface"], row["ip_address"])

use_textfsm=True requires ntc-templates to be importable in the same interpreter as Netmiko. If it silently returns raw text, that is the usual cause.

Writing a template when none exists

Value INTERFACE (\S+)
Value IP_ADDRESS (\S+)
Value STATUS (.+?)
Value PROTO (\S+)

Start
  ^Interface\s+IP-Address.*$$ -> Interfaces
  ^. -> Error

Interfaces
  ^${INTERFACE}\s+${IP_ADDRESS}\s+\S+\s+\S+\s+${STATUS}\s+${PROTO}\s*$$ -> Record
  ^\s*$$ -> Record
  ^. -> Error
# test outside any framework
textfsm show_ip_int_brief.template captured_output.txt

# then drop it in a directory and point NTC-Templates at it
export NET_TEXTFSM=/opt/ntc-templates/templates
python3 -c "from ntc_templates.parse import parse_output; print(parse_output('cisco_ios','show ip interface brief', open('captured_output.txt').read()))"

Two habits make templates robust: match on the header line before entering the data state (so the regex only applies to rows, not to banners), and allow blank lines to record rather than error. The alternative is a template that works on one device version and fails on the next.

Where TextFSM fits versus Genie

  • TextFSM — flat records, minimal dependencies, hundreds of ready templates, ideal for CMDB sync, reports and CSV/pandas output.
  • Genie (pyATS) — nested structures that mirror the operational data model, better for complex multi-table commands and multi-platform normalisation, at the cost of a heavy install.
  • Pick per command, not per project: a parsing map keyed by command that routes to TextFSM, Genie or raw output is a common and effective pattern.

Related reading: Netmiko Python network automation, pyATS and Genie: parsing show commands and state diff, and Nornir network automation inventory and tasks.

原文链接:https://github.com/networktocode/ntc-templates