使用pexpect自動登陸ssh,interact以後shell窗口太小的問題

使用Python的Pexpect模塊執行SSH登錄

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
相關文章
相關標籤/搜索