0

我正在使用 Python/Pexpect 向多个路由器生成 SSH 会话。该代码适用于一个路由器,但 session.before 的输出将与某些路由器不同步,因此它将返回前一个发送线路的输出。发送空行 (sendline()) 时尤其如此。有人有什么想法吗?任何见解将不胜感激。

以下是我所看到的示例:

ssh_session.sendline('sh version')
while (iresult==2):
    iresult = ssh_session.expect(['>','#','--More--'],timeout=SESSION_TIMEOUT)
    debug_print("execute_1 " + str(iresult))
    debug_print("execute_bef " + ssh_session.before)
    debug_print("execute_af " + ssh_session.after)

    thisoutput = ssh_session.before
    output += thisoutput

    if(iresult==2):
        debug_print("exec MORE")
        ssh_session.send(" ")
    else:
        debug_print("exec: end loop")

for cmd in config_commands:
    debug_print("------------------------------------------------\n")
    debug_print ("running command " + cmd.strip() + "\n")
    iresult=2
    ssh_session.sendline(cmd.strip())
    while (iresult==2):
        iresult = ssh_session.expect([prompt+">",prompt+"#"," --More-- "],timeout=SESSION_TIMEOUT)
        thisoutput = ssh_session.before
        debug_print("execute_1 " + str(iresult))
        debug_print("execute_af " + ssh_session.after)
        debug_print("execute_bef " + thisoutput)
        thisoutput = ssh_session.before
        output += thisoutput

        if(iresult==2):
           debug_print("exec MORE")
           ssh_session.send(" ")
        else:
           debug_print("exec: end loop")


I get this:

logged in
exec: sh version
execute_1 1
execute_bef 
R9
execute_af #
exec: end loop
------------------------------------------------

running command config t

execute_1 1
execute_af #
execute_bef sh version
Cisco IOS Software, 1841 Software (C1841-IPBASEK9-M), Version 15.1(4)M4, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport...
4

4 回答 4

1

我遇到了类似的问题。我尝试等待命令打印在屏幕上并发送输入。

我你想执行说命令'cmd',然后你做:

    session.send(cmd)
    index = session.expect([cmd, pexpect.TIMEOUT], 1)
    session.send('\n')
    index = session.expect([whatever you expect])

为我工作。

于 2013-07-05T07:42:51.113 回答
1

我以前用 pexpect 遇到过这个问题(我试图记住我是如何解决它的)。

您可以通过发送返回然后在循环中等待提示来重新与终端会话同步。当期望超时时,您就知道您已同步。

根本原因可能是您是:

  • 在没有匹配期望的情况下调用发送(因为您不关心输出)

  • 运行一个产生输出的命令,但期望在该输出中间有一个模式,然后不到输出末尾的下一个提示。解决此问题的一种方法是将您的期望模式更改为“(.+)PROMPT” - 这将一直期待到下一个提示并捕获发送的命令的所有输出(您可以在下一步中解析)。

于 2012-09-20T13:43:54.097 回答
0

我不确定这是您问题的根源,但可能值得一试。

我遇到的情况是,当您生成一个以 shell 开头或将您置于 shell 中的会话时,您必须处理 TERM 类型的怪癖(vt220、color-xterm 等)。您将看到用于移动光标或更改颜色的字符。几乎可以保证问题会随着提示出现;由于颜色更改的处理方式,您正在寻找用于识别提示的字符串出现两次(发送提示,然后编码退格,更改颜色,然后再次发送提示......但期望看到两个实例迅速的)。

这是处理这个问题的东西,保证是丑陋的,hacky,不是很 Pythonic 和功能:

import pexpect

# wait_for_prompt: handle terminal prompt craziness
#   returns either the pexpect.before contents that occurred before the 
#   first sighting of the prompt, or returns False if we had a timeout
#
def wait_for_prompt(session, wait_for_this, wait_timeout=30):
    status = session.expect([wait_for_this, pexpect.TIMEOUT, pexpect.EOF], timeout=wait_timeout)
    if status != 0:
        print 'ERROR : timeout waiting for "' + wait_for_this + '"'
        return False
    before = session.before # this is what we will want to return
    # now look for and handle any additional sightings of the prompt
    while True:
        try:
            session.expect(wait_for_this, timeout=0.1)
        except:
            # we expect a timeout here. All is normal. Move along, Citizen.
            break # get out of the while loop
        return before

s = pexpect.spawn('ssh me@myserver.local')
s.expect('password') # yes, we assume that the SSH key is already there
                     # and that we will successfully connect. I'm bad.
s.sendline('mypasswordisverysecure') # Also assuming the right password
prompt = 'me$'
wait_for_prompt(s, prompt)
s.sendline('df -h') # how full are my disks?
results = wait_for_prompt(s, prompt)
if results:
    print results
    sys.exit(0)
else:
    print 'Misery. You lose.'
    sys.exit(1)
于 2015-05-29T19:43:25.417 回答
0

我知道这是一个旧线程,但我在网上没有找到太多关于这个的信息,我只是通过自己的快速和肮脏的解决方法解决了这个问题。我还使用 pexpect 来运行网络设备列表并记录统计信息等,而且我的 pexpect.spawn.before 有时也会不同步。由于某种原因,这种情况经常发生在更快、更现代的设备上。

我的解决方案是在每个命令之间写一个空回车,并检查 .before 变量的 len() 。如果它太小,则意味着它只捕获了提示,这意味着它必须至少是实际 ssh 会话后面的一个命令。如果是这种情况,程序会发送另一个空行来将我想要的实际数据移动到 .before 变量中:

def new_line(this, iteration):
    if iteration > 4:
        return data
    else:
        iteration+=1
        this.expect(":")
        this.sendline(" \r")
        data = this.before
        if len(data) < 50:
        # The numer 50 was chosen because it should be longer than just the hostname and prompt of the device, but shorter than any actual output
            data = new_line(this, iteration)
        return data

def login(hostname):
    this = pexpect.spawn("ssh %s" % hostname)
    stop = this.expect([pexpect.TIMEOUT,pexpect.EOF,":"], timeout=20)
    if stop == 2:
        try:
            this.sendline("\r")
            this.expect(":")
            this.sendline("show version\r")
            version = new_line(this,0)
            this.expect(":")
            this.sendline("quit\r")
            return version
        except:
            print 'failed to execute commands'
            this.kill(0)
    else:
        print 'failed to login'
        this.kill(0)

我通过一个递归命令来完成此操作,该命令将调用自身,直到 .before 变量最终捕获命令的输出,或者直到它调用自身 5 次,在这种情况下它只是放弃了。

于 2017-08-11T13:44:42.420 回答