簡體   English   中英

輸出不同步之前的Python / Pexpect

[英]Python / Pexpect before output out of sync

我正在使用Python / Pexpect生成到多個路由器的SSH會話。 該代碼將適用於一個路由器,但是session.before的輸出將與某些路由器不同步,因此它將返回前一個sendline的輸出。 發送空白行(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遇到過這個問題(並且我想記住自己是如何工作的)。

您可以通過發送返回值,然后在循環中期待提示來與終端會話重新同步。 當期望超時時,您就知道自己已同步。

根本原因可能是您是:

  • 調用send時沒有預期的匹配(因為您不關心輸出)

  • 運行一個產生輸出的命令,但期望在該輸出的中間有一個模式,然后不要到輸出末尾的下一個提示符。 解決此問題的一種方法是將您的期望模式更改為“(。+)PROMPT”-這將一直等到下一個提示符並捕獲已發送命令的所有輸出(您可以在下一步中進行分析)。

我遇到了類似的問題。 我嘗試等待命令在屏幕上打印並發送回車。

我要執行命令“ cmd”,然后執行以下操作:

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

為我工作。

我不確定這是否是您問題的根源,但可能值得嘗試。

我遇到的一個問題是,當您生成一個以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)

我知道這是一個舊線程,但是在網上並沒有太多了解,我只是為此做出了自己的快速變通方法。 我還使用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次為止,在這種情況下,它只是放棄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM