Pexpect 的使用範圍很廣,能夠用來實現與 ssh, ftp , telnet 等程序的自動交互;能夠用來自動複製軟件安裝包並在不一樣機器自動安裝;還能夠用來實現軟件測試中與命令行交互的自動化。python
下載安裝:ios
download pexpect-2.3.tar.gz tar zxvf pexpect-2.3.tar.gz cd pexpect-2.3 python setup.py install (do this as root)
其實這個過程一點都不難,惟一的問題就是登錄以後終端尺寸的大小(我理解是buffer),由於Pexpect在代碼裏面有hardcode,把終端尺寸默認設成(24, 80)了。因此你連上後打開emacs會發現,emacs只佔據了整個終端的一小部分。bash
# pexpect hard-codes the terminal size as (24,80) (rows,columns). # This causes problems because any line longer than 80 characters gets # completely overwrapped on the printed outptut (even though # internally the code runs fine). We reset this to 99 rows X 200 # columns (arbitrarily chosen), which should avoid problems in all # reasonable cases. c.setwinsize(24,80)
OK, 知道問題了咱們能夠開始解決,既然支持child.setwinsize(),那咱們就想辦法獲取當前終端大小,而且在ssh目標主機以後設置終端大小。app
# 獲取窗口大小 def getwinsize(): """This returns the window size of the child tty. The return value is a tuple of (rows, cols). """ if 'TIOCGWINSZ' in dir(termios): TIOCGWINSZ = termios.TIOCGWINSZ else: TIOCGWINSZ = 1074295912L # Assume s = struct.pack('HHHH', 0, 0, 0, 0) x = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s) return struct.unpack('HHHH', x)[0:2]
# 設置大小 child.expect('-bash-baidu-ssl.*') child.sendline('ssh ' + host) winsize = getwinsize(); child.setwinsize(winsize[0], winsize[1])
OK, 一切正常。打開emacs,感受很幸福,但鏈接後我發現鏈接以前終端窗口原本就很小,如今想把窗終窗口最大化,一試就杯具了,窗口的確最大化了,可是emacs所佔區域仍舊沒有變化,也就是說鏈接後的子窗口尺寸和當前窗口尺雨不匹配,Signal終於要派上用場了:ssh
def sigwinch_passthrough (sig, data): winsize = getwinsize() global child child.setwinsize(winsize[0],winsize[1])
最後監聽事件:ide
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
一切正常!測試
下面貼上全部代碼:this
#!/usr/bin/python import sys import time import pexpect import os import struct import fcntl import termios import signal def sigwinch_passthrough (sig, data): winsize = getwinsize() global child child.setwinsize(winsize[0],winsize[1]) def getwinsize(): """This returns the window size of the child tty. The return value is a tuple of (rows, cols). """ if 'TIOCGWINSZ' in dir(termios): TIOCGWINSZ = termios.TIOCGWINSZ else: TIOCGWINSZ = 1074295912L # Assume s = struct.pack('HHHH', 0, 0, 0, 0) x = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s) return struct.unpack('HHHH', x)[0:2] if __name__ == '__main__': user = 'username' passwd = 'password' host = 'example.com' print 'ssh ' + user + '@' + host + ' ...' time.sleep(1) child = pexpect.spawn('ssh relay', env = {"TERM" : "xterm-256color"}) signal.signal(signal.SIGWINCH, sigwinch_passthrough) if len(sys.argv) > 1: child.expect("Enter PASSCODE:") child.sendline("PIN-CODE" + sys.argv[1]) child.expect('-bash-baidu-ssl.*') child.sendline('ssh ' + host) winsize = getwinsize(); child.setwinsize(winsize[0], winsize[1]) child.expect('.*password:.*') child.sendline(passwd) child.interact() pass