You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Paramiko中SSHClient.exec_command与invoke_shell.send的差异及设备适配问题

Key Differences Between exec_command() and invoke_shell() + send() in Paramiko, Explained for Your MikroTik/Cisco Issue

Great question! I’ve run into this exact behavior with network devices before, so let’s break down what’s going on here.

Core Differences Between the Two Methods

1. How They Execute Commands

  • exec_command(): Think of this as running a single, standalone command over SSH. It creates a dedicated "exec" channel for each command, runs it, captures the output, and then closes the channel. No persistent session state is kept between calls—each command starts fresh, like opening a new SSH window, running one command, and closing it immediately.
  • invoke_shell() + send(): This spins up an interactive shell session, just like when you manually SSH into a device and type commands one after another. All commands you send() run in the same session, so context (like being in a specific configuration mode) is preserved. You have to handle the back-and-forth: sending commands, waiting for prompts, parsing mixed output, and dealing with any interactive prompts (like "Are you sure?").

2. Why They Behave Differently on MikroTik vs. Cisco

The root issue here is how each device’s CLI is designed:

MikroTik RouterOS

MikroTik’s CLI is flat by default—most configuration commands (like ip route add, interface vlan add) can be run directly from the main login prompt, no need to switch into a special configuration mode.

  • exec_command() works perfectly because it sends a single command, the device executes it immediately, and returns the output.
  • When using invoke_shell() + send(), you’re probably missing a critical detail: you need to end each command with a newline (\r\n) so the device knows to process it. Also, MikroTik’s shell can be picky about timing—if you send commands too fast without waiting for the prompt to appear, the device might not register them. For example, sending ip route add ... without \r\n or before the [admin@MikroTik] > prompt shows up will leave the command hanging unexecuted.

Cisco IOS/IOS-XE

Cisco’s CLI is mode-based, which is the opposite of MikroTik. To run configuration commands (like ip route, vlan database), you first need to:

  1. Enter privileged EXEC mode with enable
  2. Switch to global configuration mode with configure terminal
  • exec_command() fails here because each call is a fresh session. If you send ip route ... directly, it runs in user EXEC mode (which doesn’t allow configuration commands), and you’ll get an error like "% Invalid input detected at '^' marker." Even if you try to chain commands (e.g., enable; configure terminal; ip route ...), Cisco’s CLI doesn’t handle this well across separate exec channels, and you’ll hit issues with interactive prompts (like entering the enable password).
  • invoke_shell() works because you can build the session step-by-step: send enable, wait for the password prompt, send the password, wait for #, send configure terminal, wait for (config)#, then send your configuration commands. The session keeps track of which mode you’re in, so commands execute as expected.

3. Output Handling

  • exec_command(): Output is clean and separated per command—you can read stdout and stderr directly to get the exact result of that one command. No mixing of prompts or previous command outputs.
  • invoke_shell(): All output (commands you sent, prompts, error messages, results) comes through a single stream. You have to write code to parse this output, identify when the device is ready for the next command, and extract the actual result from the noise of prompts and echoed commands.

Quick Fixes for Your Use Case

  • For MikroTik with invoke_shell(): Always append \r\n to your commands, and add logic to wait for the device’s prompt before sending the next command. Example snippet:
    import time
    from paramiko import SSHClient, AutoAddPolicy
    
    ssh = SSHClient()
    ssh.set_missing_host_key_policy(AutoAddPolicy())
    ssh.connect("mikrotik-ip", username="admin", password="your-pass")
    
    shell = ssh.invoke_shell()
    # Wait for initial prompt to appear
    while not shell.recv_ready():
        time.sleep(0.1)
    # Send command with newline trigger
    shell.send("ip route add dst-address=192.168.1.0/24 gateway=10.0.0.1\r\n")
    # Wait for command to execute and prompt to return
    while not shell.recv_ready():
        time.sleep(0.1)
    output = shell.recv(65535).decode()
    print(output)
    
    ssh.close()
    
  • For Cisco with exec_command(): If you really want to use it, you’ll need to enable a pseudo-terminal with get_pty=True and handle interactive prompts. But honestly, invoke_shell() (or a dedicated library like Netmiko, which wraps Paramiko for network devices) is way more reliable for Cisco’s mode-based CLI.

内容的提问来源于stack exchange,提问作者Adhy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 06:35:48