python--pexpect


  大家好,最近工作比較忙,所以沒時間來更新博客。趁着還沒在下個版本來臨之前,來這邊再更新更新。是之前學習到的一些老知識點,就當來鞏固一下了。開心QAQ

今天給大家介紹的是--Pexpect

Expect 程序主要用於人機對話的模擬
    1.運行程序 
    2.程序要求人的判斷和輸入 
    3.Expect 通過關鍵字匹配 
    4.根據關鍵字向程序發送符合的字符串 

基本使用流程

基本使用流程
    1.首先用 spawn 來執行一個程序 
    2.然后用 expect 來等待指定的關鍵字,這個關鍵字是被執行的程序打印到標准輸出上面的 
    3.最后當發現這個關鍵字以后,根據關鍵字用 send 方法來發送字符串給這個程序 

以下就是代碼了,比較簡單。但很實用

#-*- coding:utf-8 -*-
""" This runs a command on a remote host using SSH. At the prompts enter hostname, user, password and the command. """
 
import pexpect import getpass, os #user: ssh 主機的用戶名 #host:ssh 主機的域名 #password:ssh 主機的密碼 #command:即將在遠端 ssh 主機上運行的命令
def ssh_command (user, host, password, command): """ This runs a command on the remote host. This could also be done with the pxssh class, but this demonstrates what that class does at a simpler level. This returns a pexpect.spawn object. This handles the case when you try to connect to a new host and ssh asks you if you want to accept the public key fingerprint and continue connecting. """ ssh_newkey = 'Are you sure you want to continue connecting'
    # 為 ssh 命令生成一個 spawn 類的子程序對象.
    child = pexpect.spawn('ssh -l %s %s %s'%(user, host, command)) i = child.expect([pexpect.TIMEOUT, ssh_newkey, 'password: ']) # 如果登錄超時,打印出錯信息,並退出.
    if i == 0: # Timeout
        print 'ERROR!'
        print 'SSH could not login. Here is what SSH said:'
        print child.before, child.after return None # 如果 ssh 沒有 public key,接受它.
    if i == 1: # SSH does not have the public key. Just accept it.
        child.sendline ('yes') child.expect ('password: ') i = child.expect([pexpect.TIMEOUT, 'password: ']) if i == 0: # Timeout
            print 'ERROR!'
            print 'SSH could not login. Here is what SSH said:'
            print child.before, child.after return None # 輸入密碼.
 child.sendline(password) return child def main (): # 獲得用戶指定 ssh 主機域名.
    host = '10.240.176.172'
    # 獲得用戶指定 ssh 主機用戶名.
    user = 'root'
    # 獲得用戶指定 ssh 主機密碼.
    password = 'tester'
    # 獲得用戶指定 ssh 主機上即將運行的命令.
    command = 'ls -a /home' child = ssh_command (user, host, password, command) # 匹配 pexpect.EOF
 child.expect(pexpect.EOF) # 輸出命令結果.
    print child.before if __name__ == '__main__': try: main() except Exception, e: print str(e) #traceback.print_exc()
        os._exit(1)

需要注意的知識點:

spawn() 方法用來執行一個程序,打開一個到 (user, host, command) 服務器的 ssh 連接
spawn() ,或者說 pexpect 並不會轉譯任何特殊字符
process = pexpect.spawn('/bin/bash –c "ls –l | grep LOG > log_list.txt"')  or 
cmd = "ls –l | grep LOG > log_list.txt"
process = pexpect.spawn("/bin/bash", ["-c", cmd])
process.expect(pexpect.EOF)

timeout - 超時時間
默認值: 30 (單位:秒)

maxread - 緩存設置
默認值: 2000 (單位:字符)
指定一次性試着從命令輸出中讀多少數據。如果設置的數字比較大,那么從 TTY 中讀取數據的次數就會少一些。
設置為 1 表示關閉讀緩存

logfile - 運行輸出控制
默認值: None
process = pexpect.spawn("ftp sw-tftp", logfile=sys.stdout) 如果你想看到spawn過程中的輸出,那么可以將這些輸出寫入到 sys.stdout
process = pexpect.spawn("ftp sw-tftp")
logFileId = open("logfile.txt", 'w')
process.logfile = logFileId

logfile_read - 獲取標准輸出的內容
默認值: None
記錄執行程序中返回的所有內容,也就是去掉你發出去的命令,而僅僅只包括命令結果的部分:
process.logfile_read = sys.stdout

cwd - 指定命令執行的目錄
默認值: None 或者說 ./
sendline("ls –l", cwd="/etc")   在 /etc 目錄下執行 ls –l 命令
expect() - 關鍵字匹配
后面的匹配關鍵字是一個列表的話,就會返回一個數字表示匹配到了列表中第幾個關鍵字,從 0 開始計算。
index = process.expect([
    'Permission Denied',
    'Terminal type',
    'ftp>',
])
if index == 0:
    print "Permission denied at host, can't login."
    process.kill(0)
elif index == 1:
    print "Login ok, set up terminal type…"
    process.sendline('vty100')
    process.expect("ftp>")
elif index == 2:
    print "Login Ok, please send your command"
    process.interact()
0.權限不足,這可能是ftp服務器出現問題,或者沒有這個帳號,或者其他什么情況,反正只要發現這種情況的話,我們就給用戶提示一下,
然后殺掉這個進程
1.登陸成功,但還要用戶指定終端模式才能真正使用,所以我們在代碼中指定了 vty100 這種模式,然后看是不是能真正使用了
2.還是登陸成功了,而且還可以直接輸入命令操作 ftp 服務器了,於是我們提示用戶,然后把操作權限交給用戶

另外有一種特殊情況,如果同時有2個被匹配到,那么怎么辦?簡單來說就是這樣:
原始流中,第一個被關鍵字匹配到的內容會被使用
匹配關鍵字列表中,最左邊的會被使用

child.expect(['(?i)etc', '(?i)readme', pexpect.EOF, pexpect.TIMEOUT])
前 2 個匹配都是大小寫無關的,關鍵就是這個 (?i) 匹配規則,它相當於 re.IGNORE 或者 re.I 這個關鍵字

send() - 發送關鍵字
send() 作為3個關鍵操作之一,用來向程序發送指定的字符串,它的使用沒什么特殊的地方,比如:

process.expect("ftp>")
process.send("by\n")

sendline() - 發送帶回車符的字符串
sendline() 和 send() 唯一的區別就是在發送的字符串后面加上了回車換行符,這也使它們用在了不同的地方:

只需要發送字符就可以的話用send()
如果發送字符后還要回車的話,就用 sendline()

特殊變量
pexpect.EOF - 匹配終止信號
pexpect.TIMEOUT - 匹配超時信號

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM