输出不同步之前的Python/Pexpect

输出不同步之前的Python/Pexpect,python,pexpect,Python,Pexpect,我正在使用Python/Pexpect为多个路由器生成一个SSH会话。该代码将适用于一个路由器,但session.before的输出将与某些路由器不同步,因此它将返回来自前一个发送线的输出。发送空行(sendline())时,情况似乎尤其如此。有人有什么想法吗?任何见解都将不胜感激 下面是我所看到的示例: ssh_session.sendline('sh version') while (iresult==2): iresult = ssh_session.expect(['>',

我正在使用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...

我以前在pexpect中遇到过这个问题(我正在努力回忆我是如何解决这个问题的)

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

根本原因可能是您:

  • 在没有匹配expect的情况下调用send(因为您不关心输出)

  • 运行一个命令,该命令在输出的中间产生输出,但期望一个模式,而不是输出结束时的下一个提示符。处理此问题的一种方法是将expect模式更改为“(.+)提示符”-这将在下一个提示符之前一直使用,并捕获所发送命令的所有输出(您可以在下一步中解析)


    • 我也面临类似的问题。我试图等待命令打印在屏幕上,然后发送回车

      如果要执行say命令'cmd',则执行以下操作:

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

      为我工作。

      我不确定这是你问题的根源,但也许值得一试

      我遇到的一件事是,当您生成一个以shell开始或将您放入shell的会话时,您必须处理术语类型(vt220、color xterm等)的怪癖。您将看到用于移动光标或更改颜色的字符。问题几乎肯定会随着提示出现;由于处理颜色更改的方式,您要查找的用于标识提示的字符串出现了两次(提示被发送,然后编码为backspace,更改颜色,然后再次发送提示…但是expect会同时看到提示的两个实例)

      这里有一些东西可以处理这个问题,保证是丑陋的、黑客的、不太像蟒蛇的和功能性的:

      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)
      

      我知道这是一个旧的线程,但我没有在网上找到太多关于这一点,我只是通过制定自己的快速和肮脏的解决办法。我还使用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)
      
      def新行(本次迭代):
      如果迭代>4:
      返回数据
      其他:
      迭代次数+=1
      这个。期望(“:”)
      此.sendline(“\r”)
      data=此参数
      如果len(数据)<50:
      #之所以选择数字50,是因为它应该比设备的主机名和提示符长,但比任何实际输出都短
      数据=新线(本次迭代)
      返回数据
      def登录(主机名):
      this=pexpect.spawn(“ssh%s”%hostname)
      stop=this.expect([pexpect.TIMEOUT,pexpect.EOF,“:”],TIMEOUT=20)
      如果停止=2:
      尝试:
      此.sendline(“\r”)
      这个。期望(“:”)
      此.sendline(“显示版本\r”)
      版本=新的_行(此,0)
      这个。期望(“:”)
      此.sendline(“退出\r”)
      返回版本
      除:
      打印“无法执行命令”
      这个。杀死(0)
      其他:
      打印“登录失败”
      这个。杀死(0)
      

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

      感谢重新同步的想法,我认为这很难看,但对我来说很有效。