Sample code for 30+ languages & platforms
Zig

SSH Commands to a Cisco Switch

See more SSH Examples

Demonstrates establishing an SSH session with a Cisco switch (or similar device) and sending commands in a device console session. Each command is sent, and its output is read up to the device's next prompt.

Note: QuickShell allocates a PTY, which is what a network device console expects. The device presents an interactive prompt, and each command's output is read up to the next prompt.

Background: Network devices differ from general-purpose servers in that they expose a menu- or prompt-driven console rather than a Unix shell, so exec requests are usually unavailable and driving the interactive console is the only option. That makes prompt matching the synchronization mechanism, and it is why a PTY is appropriate here despite the general advice to avoid one. Retrieving the received text between commands is essential: a prompt left in the buffer would make the next receive return immediately with the wrong output.

Chilkat Zig Downloads

Zig
const std = @import("std");
const chilkat = @import("chilkat");

pub fn main(init: std.process.Init) !void {
    const alloc = init.arena.allocator();

    // This example requires the Chilkat API to have been previously unlocked.
    // See Global Unlock Sample for sample code.

    // Demonstrates establishing an SSH session with a Cisco switch (or similar device) and sending
    // commands in a device console session.
    //
    // Note: QuickShell allocates a PTY, which is what a network device console expects.  The device
    // presents an interactive prompt, and each command's output is read up to the next prompt.

    const ssh = try chilkat.Ssh.init();
    defer ssh.deinit();

    const port = 22;
    ssh.connect("172.16.16.100", port) catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    // Normally you would not hard-code the password in source.  You should instead obtain it
    // from an interactive prompt, environment variable, or a secrets vault.
    const password = "mySshPassword";

    ssh.authenticatePw("mySshLogin", password) catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    // Start a shell session.
    const channel_num = ssh.quickShell();
    if (channel_num < 0) {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    }

    // IMPORTANT: Set a read timeout before receiving until a match.  ReadTimeoutMs defaults to 0,
    // which means no limit -- without it, this call waits forever if the received data never
    // contains a match.
    ssh.setReadTimeoutMs(15000);

    const case_sensitive = true;

    // The switch presents a prompt ending in "#".  Reading up to it confirms the session is ready.
    ssh.channelReceiveUntilMatch(channel_num, "#", "utf-8", case_sensitive) catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    var cmd_output: [:0]const u8 = ssh.getReceivedText(alloc, channel_num, "utf-8") catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    std.debug.print("{s}\n", .{cmd_output});

    // Send a command and read its output up to the next prompt.
    ssh.channelSendString(channel_num, "show clock\n", "utf-8") catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    ssh.channelReceiveUntilMatch(channel_num, "#", "utf-8", case_sensitive) catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    // Retrieving the text also clears the receive buffer, which matters: if the prompt were left
    // buffered, the next receive would match it immediately and return the wrong output.
    cmd_output = ssh.getReceivedText(alloc, channel_num, "utf-8") catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    std.debug.print("{s}\n", .{cmd_output});

    // Additional commands follow the same send / read-to-prompt / retrieve pattern.
    ssh.channelSendString(channel_num, "show version\n", "utf-8") catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    ssh.channelReceiveUntilMatch(channel_num, "#", "utf-8", case_sensitive) catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    cmd_output = ssh.getReceivedText(alloc, channel_num, "utf-8") catch {
        std.debug.print("{s}\n", .{try ssh.getLastErrorText(alloc)});
        return;
    };

    std.debug.print("{s}\n", .{cmd_output});

    ssh.disconnect();
}