//by Chaos
謝絕轉(zhuǎn)載
詳細(xì)的內(nèi)容可以參考下面的參考文檔搀绣,下面的內(nèi)容主要是為網(wǎng)絡(luò)設(shè)備運(yùn)維人員使用的pexpect 跨平臺簡明教程。
基本概念:
pexpect是什么
Expect 程序主要用于人機(jī)對話的模擬蔗包,就是那種系統(tǒng)提問,人來回答 yes/no 昆码,或者賬號登錄輸入用戶名和密碼等等的情況气忠。
pexpect是 Don Libes 的 Expect 語言的一個 Python 實(shí)現(xiàn),是一個用來啟動子程序,并使用正則表達(dá)式對程序輸出做出特定響應(yīng)赋咽,以此實(shí)現(xiàn)與其自動交互的 Python 模塊旧噪。它可以用來實(shí)現(xiàn)與ssh, ftp, telnet等程序的自動交互。
pexpect主要模塊
- pexpect.spawn 創(chuàng)建一個子程序child脓匿,執(zhí)行一個程序
- child.sendline(或send)是在子程序中輸入command淘钟,用 send 方法來發(fā)送字符串給這個程序
- child.expect用 expect 來等待指定的關(guān)鍵字,這個關(guān)鍵字是被執(zhí)行的程序打印到標(biāo)準(zhǔn)輸出上面的
child.buffer child.before child.after
send命令后執(zhí)行結(jié)果內(nèi)容保存在buffer中陪毡,這時child.expect('keyword')后米母,child.before即為“keyword”之前的字符串,child.after即為匹配的”keyword”字符串毡琉。
command的執(zhí)行結(jié)果都保存在一個buffer中铁瞒,每次執(zhí)行expect時都從buffer中開始檢查匹配的pattern,如果找到了匹配的pattern桅滋,則所有在匹配處之前的內(nèi)容都從buffer中清除慧耍。
(這邊沒有看明白也沒有關(guān)系身辨,可以看后面的實(shí)踐篇例子)
一些需要強(qiáng)調(diào)的細(xì)節(jié)
跨平臺使用
通常維護(hù)人員有的偏向于用WIN系統(tǒng),有的偏向于LINUX系統(tǒng)芍碧。所以前期團(tuán)隊(duì)希望形成一個統(tǒng)一框架的時候就出現(xiàn)了一個難題煌珊。框架如何適用于不同的系統(tǒng)泌豆。
LInux系統(tǒng)pexpect包定庵,win系統(tǒng)前期嘗試使用winpexpect,但是程序改動很大踪危,并沒有調(diào)試成功蔬浙。
如何在WIN系統(tǒng)使用python的pexpect包很難找到相關(guān)資料,某乎上都是類似的疑問沒有解答贞远。
團(tuán)隊(duì)成員增加后敛滋,終于有了新的思路 ,團(tuán)結(jié)就是力量兴革。
#linux系統(tǒng)采用以下判斷
if sys.platform.startswith('linux'):
print("sys.platform=linux.connect()")
tiaoban = 'ssh -o KexAlgorithms=diffie-hellman-group14-sha1 -o StrictHostKeyChecking=no -v'+TbUser+'@跳板機(jī)ip -p 跳板機(jī)端口'
child = pexpect.spawn(tiaoban)
# win系統(tǒng)采用以下判斷
elif sys.platform.startswith('win'):
print("sys.platform=windows.connect()")
tiaoban = 'plink.exe -ssh -v '+TbUser+'@跳板機(jī)ip -p 跳板機(jī)端口
child = pexpect.popen_spawn.PopenSpawn(tiaoban)
index = child.expect(["y/n", "assword:"])
通過這個模塊進(jìn)行不同系統(tǒng)的適配绎晃。
將plink.exe裝在python的文件夾在python的安裝目錄下,win系統(tǒng)可以同樣使用pexpect模塊
參考信息1:Pexpect 官方文檔 New in version 4.0: Windows support杂曲。Pexpect can be used on Windows to wait for a pattern to be produced by a child process, using [pexpect.popen_spawn.PopenSpawn
]
參考信息2:PuTTY是一個Telnet庶艾、SSH、rlogin擎勘、純TCP以及串行接口連接軟件咱揍。plink是可以獨(dú)立使用的exe實(shí)現(xiàn)形式,可以讓我們直接在命令行制定好命令棚饵,然后執(zhí)行煤裙,完成后自動關(guān)閉session。ssh是一個安全通道協(xié)議噪漾。plink是這個通道協(xié)議的一個實(shí)現(xiàn) [圖片上傳中...(image.png-572001-1587612890428-0)]
sendline() 和 send()
從官方文檔來看硼砰,
sendline() 和 send() 唯一的區(qū)別就是在發(fā)送的字符串后面加上了回車換行符,這也使它們用在了不同的地方:
只需要發(fā)送字符就可以的話用send()
如果發(fā)送字符后還要回車的話欣硼,就用 sendline()
但是在調(diào)測過程中题翰,WIN系統(tǒng)下命令輸入后,child.before始終得不到預(yù)想中的結(jié)果诈胜。
經(jīng)過逐步排查豹障,發(fā)現(xiàn)在WIN系統(tǒng)下只能使用send() ,如果使用sendline() 焦匈,第一次交互沒有問題血公,后續(xù)交互就開始問題。
WIN系統(tǒng)下child.before輸出類型
WIN系統(tǒng)下child.before輸出為b'byte型缓熟,做判斷時要轉(zhuǎn)為str型累魔。具體可以參考最后面一篇講編碼類型的文章岩饼,講的很詳細(xì)。
child.before.decode(encoding="ascii")
child.before child.after實(shí)踐
例子1
child.sendline('%s' % dev)
index=child.expect(['me:','in:'])
child.send(MANUser + '\r')
child.expect('assword:')
child.send(MANPass + '\r')
child.expect(['>', '#'])
print("login succ!")
send Username后,child.before一直到'Tac_Userna',child.after為‘me:’,child.buffer為空薛夜。
expect關(guān)鍵字assword:后,child.before回顯一直到keyword之前版述,child.after為keyword梯澜,child.buffer為空。
expect關(guān)鍵字#后渴析,child.before回顯一直到keyword之前晚伙,child.after為keyword,child.buffer為空俭茧。
例子2
child.send(Command+ '\r')
child.expect('>')
下發(fā)command命令咆疗,child.before維持原來的不變,expect到keyword以后母债,child.before變?yōu)橄掳l(fā)command命令后的設(shè)備回顯午磁。
參考文檔