Paramiko .recv 未读取使用 .send [重复] 执行的命令的完整输出

问题描述 投票:0回答:2

我有一个问题,以下功能

remote.send("show run int vlan 1\\n")

不起作用。代码如下。它能够读取文件、创建新文件以及写入和保存文件。然而,输出仅包含开关名称,没有其他内容,有时它会显示开关名称和命令的一个或两个字符。输出如下

switch test1
IP address 1.1.1.51
test1_2023-02-23
Successfully log in to test1
test1#s
switch test2
IP address 1.1.1.50
Test2_2023-02-23
Successfully log in to test2
test2#

刚开始学习语言,我不确定问题是什么。预先感谢您。

myfile = open('c:\znet\device-list.txt','r')

count = 0

while True:
    count = count + 1
    line = myfile.readline()
    if not line:break
    else:
        x = line.strip()
        y,z =x.split(",",1)
        print ("switch ",y)
        print ("IP address ",z)
        backupdate = str(date.today())
        filename = y + "_" + backupdate
        print (filename)
        host = z
        user = 'cisco'
        password = 'cisco'
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
        client.connect(hostname=host, username=user, password=password)
        print ("Successfully log in to", y)
        remote = client.invoke_shell()
        remote.send("show run int vlan 1\n")
        output = remote.recv(1048576)
        print (output.decode('ascii'))
        with open("{}.txt".format(filename),"w") as f:
            print (output.decode('ascii'),file=f)

我希望在终端和创建的文件中看到 vlan 1 (

show run int vlan 1
) 的配置。

python ssh paramiko cisco
2个回答
0
投票

Martin 是正确的,我已经编写了一些代码,当设备将数据发送回 SSH 通道时,这些代码将有助于检查和收集数据。代码有注释,应该是有意义的。

import paramiko, time

HOST = "x.x.x.x"
PORT = 22
USERNAME = "xxx"
PASSWORD = "xxx"

def ClearBuffer(connection: paramiko.Channel, sleeptime: float, lookfor: str):
    # This will get rid of all the login information, like banners etc.
    buffer: str = ""
    timer: float = 0.0
    error: int = 0
    errorDescription: str = ""
    while not buffer.endswith(lookfor):
        if timer > 10.0:
            error: int = 1
            errorDescription: str = "Reached command timeout"
            break
        if connection.recv_ready():
            buffer += connection.recv(65535).decode()
        time.sleep(sleeptime)
        timer += sleeptime
    return(buffer) if error != 1 else errorDescription

def ExecuteSingleCommand(connection: paramiko.Channel, command: str, sleeptime: float, lookfor: str):
    buffer: str = ""
    timer: float = 0.0
    error: int = 0
    errorDescription: str = ""
    connection.send(f"{command}\n") # Send command to device and press enter (\n)
    while not buffer.endswith(lookfor): # Continuously look for lookfor, which in this case is #
        if timer > 30.0: # Set a general timer in order to stop execution after 30 seconds
            error = 1
            errorDescription = "Reached command timeout"
            break
        if connection.recv_ready(): # Check if channel has data
            buffer += connection.recv(65535).decode() # Save channel data
            if "--More--" in buffer: # Specific for Cisco devices, if 'terminal length 0' is not entered, channel waits for key press
                errorDescription = "Paging not disabled"
                break
        time.sleep(sleeptime) # wait for sleep time seconds
        timer += sleeptime
    return(buffer.strip(command).strip(lookfor).strip()) if error != 1 else errorDescription

def ExecuteCommand(cmdlist: list, sleeptime: float=0.1, lookfor: str="#"):
    # sleeptime = time to wait before checking for data
    # lookfor = the character to look for in the SSH shell to indicate the command was executed
    results: list = []
    error: int = 0
    with paramiko.SSHClient() as ssh: # Connect to devices using a context manager, which will automatically close connections
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(HOST, PORT, USERNAME, PASSWORD, timeout=300, banner_timeout=240, look_for_keys=False) # Connect to device
        connection: paramiko.Channel = ssh.invoke_shell() # Invoke shell for interactive commands
        invoke = ClearBuffer(connection, sleeptime, lookfor) # Clear the current channel buffer for login information
        if "Reached command timeout" not in invoke: # Check that clear buffer did not timeout, e.g. it couldn't find lookfor in the buffer
            for cmd in cmdlist: # Iterate every command
                cmdResult = ExecuteSingleCommand(connection, cmd, sleeptime, lookfor) # Execute every single command
                if "Reached command timeout" not in cmdResult: # Check that connection didn't time out
                    results.append(cmdResult) # Append results
                else:
                    error = 1
        else:
            error = 1
    return(results) if error != 1 else None

print(ExecuteCommand(["terminal length 0", "sh run"]))

测试结果:

['xxx-xx-3560CG-01', 'Building configuration...\r\n\r\nCurrent configuration : 5893 bytes\r\n!\r\n! Last configuration change at 09:30:59 CET Mon Jan 17 2022 by...TRUNCATED]

您应该能够优化代码并轻松地自己添加其他功能。


0
投票

recv
不会返回整个输出。这不可以。您正在使用 shell (
invoke_shell
)。 shell 是一个永无休止的间歇性数据流。唯一的结局是注销。也没有任何信号表明特定命令的完整输出已结束。
recv
返回您调用它时可用的任何数据。如果你想要完整的输出,你需要反复调用
recv
,直到得到全部。
请参阅通过 Paramiko 在 Cisco 交换机上执行多个命令 - 提高性能

这是原因之一,为什么一般来说,您不应该使用

invoke_shell
进行命令自动化。
请参阅Paramiko 上的 exec_command 和使用 invoke_shell() 发送有什么区别?

© www.soinside.com 2019 - 2024. All rights reserved.