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

如何用Python脚本连接定制Shell网络设备并执行多命令序列?

问题:Fabric连接定制Shell网络设备无法执行命令?

我有一台需通过用户名密码连接的网络设备,登录后会显示多行登录横幅,随后进入厂商预设的定制Shell。我需要在单个会话中执行一系列命令(比如先切换到IP子菜单,再执行SET IP命令),但用Fabric的Connection.run()时,只会弹出交互式Shell,没法执行指令,示例代码如下:

from fabric import Connection
from invoke.exceptions import UnexpectedExit
from invoke.watchers import Responder

def run_network_command(host, username, password, command):
    try:
        conn = Connection(host=host, user=username, connect_kwargs={
                "password": password,
            },
        )
        
        # Create responder for the custom shell prompt
        prompt_pattern = r"\[net-7\.2\] \w+>"
        shell_responder = Responder(
            pattern=prompt_pattern,
            response=f"{command}\n"
        )
        
        # Run command in the custom shell
        result = conn.run(
            command,
            pty=True,
            watchers=[shell_responder]
        )
        
        return result.stdout
        
    except UnexpectedExit as e:
        return f"Error executing command: {str(e)}"
    except Exception as e:
        return f"Connection error: {str(e)}"
    finally:
        try:
            conn.close()
        except:
            pass

# Example usage
if __name__ == "__main__":
    # Connection details
    host = "192.168.1.1"
    username = "root"
    password = "pass"
    command = "show version"
    
    # Run command and print output
    output = run_network_command(host, username, password, command)
    print(output)

解决方法

1. 核心问题分析

你的代码只处理了定制Shell的提示符,但忽略了完整的登录交互链:用户名输入提示、密码输入提示、登录横幅后的首次提示符匹配。另外,conn.run(command)是尝试在远程标准Shell执行命令,而定制Shell不支持这种调用方式,必须在交互式会话中逐步响应提示符并发送命令。

2. 关键改进方案

  • 覆盖全交互节点:针对登录时的用户名、密码提示,以及后续的Shell/子菜单提示符,分别创建Responder处理。
  • 改用conn.shell():该方法专门用于交互式会话,更适配定制Shell的场景,而非conn.run()。
  • 支持多命令序列:按顺序匹配每个步骤的提示符,依次发送命令,比如进入子菜单→执行配置→返回主菜单。

3. 修正后的代码

from fabric import Connection
from invoke.watchers import Responder
import time

def run_network_commands(host, username, password, commands):
    try:
        # 定义登录阶段的响应器
        user_responder = Responder(
            pattern=r"Username:|login:",  # 匹配设备的用户名提示
            response=f"{username}\n"
        )
        pass_responder = Responder(
            pattern=r"Password:",  # 匹配设备的密码提示
            response=f"{password}\n"
        )

        # 初始化连接
        conn = Connection(host=host, user=username, connect_kwargs={"password": password})
        
        # 启动交互式Shell会话,开启pty确保交互正常
        with conn.shell(pty=True, watchers=[user_responder, pass_responder]) as shell:
            # 等待登录横幅加载完成,确保提示符出现
            time.sleep(2)
            # 逐行发送命令序列
            for cmd in commands:
                shell.send(f"{cmd}\n")
                # 等待命令执行完成,根据设备响应速度调整sleep时长
                time.sleep(1)
            # 最后发送退出命令
            shell.send("exit\n")
            # 等待会话结束,读取所有输出
            time.sleep(1)
            output = shell.stdout.read().decode('utf-8')
        
        return output
        
    except Exception as e:
        return f"执行异常: {str(e)}"
    finally:
        try:
            conn.close()
        except:
            pass

# 示例:执行多步命令序列
if __name__ == "__main__":
    host = "192.168.1.1"
    username = "root"
    password = "pass"
    # 命令序列:查看版本 → 进入IP子菜单 → 设置IP地址 → 退出子菜单 → 退出Shell
    commands = ["show version", "ip", "set ip 192.168.1.2", "exit", "exit"]
    
    output = run_network_commands(host, username, password, commands)
    print(output)

4. 额外注意事项

  • 正则表达式匹配:要根据设备的实际输出调整pattern,比如子菜单的提示符可能是IP-SUBMENU>,需要把这类情况加入匹配规则。
  • 等待时长调整:time.sleep()的时长要根据设备的响应速度调整,避免命令发送过快导致未匹配到提示符。
  • 调试技巧:可以在启动shell时开启实时输出查看,方便调整匹配规则和等待时长。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:34:52