【问题标题】:SSH programming with Python 3 paramiko, EOFError when trying to execute commands使用 Python 3 paramiko 进行 SSH 编程,尝试执行命令时出现 EOFError
【发布时间】:2016-06-30 23:19:11
【问题描述】:

* 的向导。我正在尝试使用 paramiko 将命令从 .txt 文件读入 SSH。目前它将从文件的第一行读取并执行它。当我到达第二行时,它会抛出一个 EOFError 并退出。我检查了第二个命令是否使它打印并且它确实打印了,但是它没有执行。我希望有人能够帮助我解决这个问题。这是我的代码:

from paramiko import client
import logging
import os

#Clear the screen before starting the script
os.system('cls')

# Prompting for the user input config file
filename = input('Input configuration filename, the file extension must be attached: ')

# Creating the LOG file for the execution of the config file
logFileName = "LOG" + filename[0:]
try:
    logging.basicConfig(filename= logFileName ,format='%(asctime)s %(message)s', level= logging.DEBUG)
    print ("The file was created!")
except IOError:
    print ("File failed to create")

logging.info("---------------------------------------------------------------------------")
logging.info("NEW CONFIGURATION LOG ENTRY")
logging.info("---------------------------------------------------------------------------")


# Class for creating an SSH client, logging in, letting us write out commands, and close the client.
class ssh:
    client = None
    def __init__(self, address, username, password):


        print ("Connecting to server...")
        logging.info('Connecting to server...')

        self.client = client.SSHClient()
        self.client.set_missing_host_key_policy(client.AutoAddPolicy())
        self.client.connect(address, username= username, password= password, look_for_keys= False)

        logging.info("Address: " + address)
        logging.info("Username: " + username)
        print ("Connection successful!")
        logging.info('Connection successful!')

    def sendCommand(self, command):
        if (self.client):
            stdin, stdout, stderr = self.client.exec_command(command)
            receiveData = b""
            while not stdout.channel.exit_status_ready():
                receiveData += stdout.channel.recv(1024)

            if stdout.channel.recv_ready():
                received = stdout.channel.recv(1024)
                while received:
                    receiveData += received
                    received = stdout.channel.recv(1024)

            if receiveData:
                print (str(receiveData, "utf8"))

            else:
                print ("stdout is empty")
        else:
            print ("Connection failed, check credentials and try again..")
            logging.warning('Connection failed, check credentials and try again..')

connection = ssh('0.0.0.0', 'test', 'test')
with open(filename) as f:
    for line in f:
        print(line)
        connection.sendCommand(line)

.txt 文件的内容如下:

配置终端

接口 Gi0/9

描述测试接口

非常感谢您的帮助,谢谢。

【问题讨论】:

  • sendCommand 的当前实现有时无法接收服务器输出。和原代码一样,还是简化版?
  • @Arnial 和原版一样

标签: python ssh paramiko


【解决方案1】:

可能的错误。 sendCommand 的当前实现可能无法接收输出(或完整输出)。

原因 exit_status_ready 是一种非阻塞方式来查找接收到的退出状态。脚本可能仍未读取输出的最后一部分。如果recv_readyTrue,您需要在while 之后调用recv

另外,我不认为在 while 循环中检查 recv_ready 是个好主意。这是非阻塞方法。因为它while循环会无用地运行多次,只是浪费你的CPU能力。

这个版本适合我:

receiveData = b""
while not stdout.channel.exit_status_ready():
    receiveData += stdout.channel.recv( 2048 )

if stdout.channel.recv_ready():
    received = stdout.channel.recv( 2048 )
    while received: #received will be empty only when all data received
        receiveData += received
        received = stdout.channel.recv( 2048 )

if receiveData:
    print( str( receiveData, "utf8" ) )
else:
    print( "stdout is empty" )

我还应该提到,从输出构建字符串的方法更简单。您可以使用 stdinstdoutstderr 是类似文件的对象这一事实。

这里是stderr 的更简单示例(阅读它可能也是个好主意):

data = ""
for line in stderr:
    #line in string already (probably will work only if locale is utf8)
    data += line 

if data:
    print( data ) 
else:
    print( "stderr is empty" )

更新: 如果一行没有多个命令,那么

filename = input('Input configuration filename, the file extension must be attached: ')
# define ssh class here (i'll skip it to make it shorter)

connection = ssh('0.0.0.0', 'test', 'test')
with open(filename) as f:
   for line in f:
       connection.sendCommand( line )

如果每行有多个命令,只需将它们拆分为不同命令的数组。

【讨论】:

  • 代码将读取文件,但是如果我有 2 个或更多命令,它只会读取最后一个。这可能与我在文件中的阅读有关,但是,我不确定解决此问题的方法。
  • 尝试执行命令时出现错误,在我发布的新代码中更详细。谢谢。