Netmiko Fundamentals
Running Show Commands with Netmiko
What you'll learn
- How send_command() runs a show command and returns its output
- Why real output is raw text, not a ready-made fact like the Phase 2.6 mock returned
- How to write a small, reliable function that parses one specific fact out of real CLI text
- How to do the same for a second, different command's output
- Why this parsing step is the piece that genuinely didn't exist before this module
Listen to a guided explanation of this lesson.
Spoken narration isn't supported in this browser.
Running a command
Once a connection is open, send_command() runs a single command and returns whatever the device prints back — as plain text, exactly as it would appear on your screen in a real SSH session:
output = connection.send_command("show ntp status")
print(output)No parsing, no interpretation — output is the device's raw response, character for character, the same as if you'd typed the command yourself.
That's the real difference this lesson is about. simulate_connection(), back in "Your First Network Automation," handed back a ready-made fact: {"ntp_synced": True}. A real device doesn't do that — it hands back text a person can read, and you have to decide what that text means.
This is the piece that's genuinely new
Everything else in this module's connection code — the parameters, ConnectHandler, the try/except — closely mirrors what "Your First Network Automation" already taught. Parsing raw text into a fact is the one skill that module's mock version never needed, because it made that decision up front for you.
What the output actually looks like
Here's realistic example output for show ntp status on a Cisco IOS device — synced and unsynced, shown in the same format a real device returns:
Clock is synchronized, stratum 4, reference is 192.168.1.1
nominal freq is 250.0000 Hz, actual freq is 249.9990 Hz, precision is 2**18
reference time is DEADBEEF.12345678 (12:34:56.123 UTC Wed Jan 1 2025)
clock offset is 0.0123 msec, root delay is 12.34 msec
root dispersion is 5.67 msec, peer dispersion is 2.34 msecThe word to look for is right at the start: 'Clock is synchronized.'
Clock is unsynchronized, stratum 16, no reference clock
nominal freq is 250.0000 Hz, actual freq is 250.0000 Hz, precision is 2**18
reference time is 00000000.00000000 (00:00:00.000 UTC Mon Jan 1 1900)
clock offset is 0.0000 msec, root delay is 0.00 msec
root dispersion is 0.00 msec, peer dispersion is 0.00 msecSame command, same format — but the first line reads 'unsynchronized' instead.
Turning text into a fact
The parsing itself doesn't need anything exotic — checking whether the output starts with a specific phrase is enough:
def is_ntp_synced(show_ntp_output):
"""Check whether 'show ntp status' output indicates the clock is synchronized."""
first_line = show_ntp_output.strip().splitlines()[0] if show_ntp_output.strip() else ""
return first_line.startswith("Clock is synchronized").strip() removes any leading/trailing blank lines Netmiko sometimes includes; .splitlines()[0] takes just the first line, since that's the only one that matters here; .startswith(...) checks the exact phrase this depends on.
This function is genuinely testable without any device at all — it's just a string check, run against sample text:
synced_output = "Clock is synchronized, stratum 4, reference is 192.168.1.1\n..."
unsynced_output = "Clock is unsynchronized, stratum 16, no reference clock\n..."
print(is_ntp_synced(synced_output)) # True
print(is_ntp_synced(unsynced_output)) # FalseThis is exactly how this function was checked while writing this lesson — no device required. Parsing logic like this is worth testing this way before it's ever pointed at a real connection.
A second command, the same pattern
VLAN Name Status Ports
---- -------------------------------- --------- -------------------------------
1 default active Gi0/1, Gi0/2, Gi0/3
10 MANAGEMENT active Gi0/4
20 USERS active Gi0/5, Gi0/6Realistic 'show vlan brief' output — a header, a separator line, then one line per VLAN, starting with its ID.
def is_vlan_present(show_vlan_output, vlan_id):
"""Check whether a given VLAN ID appears in 'show vlan brief' output."""
for line in show_vlan_output.splitlines():
stripped = line.strip()
first_word = stripped.split(" ")[0] if stripped else ""
if first_word == str(vlan_id):
return True
return FalseChecking the exact first word of each line — not just whether '20' appears anywhere — matters here: a naive search for '1' would also match inside '10', '100', or a port name. Comparing the whole first word avoids that.
Key takeaways
- send_command() runs a command and returns the device's raw text response — no parsing done for you.
- This is the real difference from the Phase 2.6 mock, which handed back a ready-made fact instead of text to interpret.
- A small, focused parsing function — checking a specific phrase or an exact line's first word — is usually enough; no advanced text-processing tools are needed.
- Parsing functions are pure logic, testable against sample CLI text with no device required — worth verifying this way before pointing them at a real connection.
- Comparing an exact word, not a loose substring, avoids the classic '1 matches inside 10' parsing mistake.