预期和终端调整大小

Pexpect and Terminal Resizing

我正在使用 pexpect 自动通过 ssh 连接到提示输入密码的远程服务器。过程非常简单,效果很好:

child = pexpect.spawn("ssh -Y remote.server")
child.expect(re.compile(b".*password.*"))
child.sendline(password)
child.interact()

这很好用,但是,我注意到一个我一直无法弄清楚的非常烦人的怪癖。当我在此终端中使用 vim 时,它似乎无法正确调整大小。当直接 ssh-ing 并使用诸如 vim 之类的程序时,我可以调整终端 window(本地)的大小,而远程程序 automatically/interactively 会修复列和行。我的预期实例没有。还有一些我可以忍受的小怪癖,但是这个很烦人。

我希望找到一种方法,使我的预期 ssh 会话的行为与本机 ssh 会话的行为相同,或者至少理解两者行为不同的原因。

pexpect's docinteract() 函数下实际上有一个例子。就像编写 C 代码一样,它需要一个 SIGWINCH 处理程序。

import pexpect, struct, fcntl, termios, signal, sys

def sigwinch_passthrough (sig, data):
    s = struct.pack("HHHH", 0, 0, 0, 0)
    a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(),
                                          termios.TIOCGWINSZ , s) )
    global p
    p.setwinsize(a[0], a[1])

# Note this 'p' global and used in sigwinch_passthrough.
p = pexpect.spawn('/bin/bash')
signal.signal(signal.SIGWINCH, sigwinch_passthrough)

p.interact()

SIGWINCH 处理 window 尺寸变化。如果你需要它的行为与原生 ssh 相同,你还应该设置 pexpect initial window size:

import pexpect, struct, fcntl, termios, signal, sys

def get_terminal_size():
    s = struct.pack("HHHH", 0, 0, 0, 0)
    a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s))
    return a[0], a[1]

def sigwinch_passthrough(sig, data):
    global p
    if not p.closed:
        p.setwinsize(*get_terminal_size())

p = pexpect.spawn('/bin/bash')
# Set the window size the same of current terminal window size
p.setwinsize(*get_terminal_size())
# Hook the window change signal so that the pexpect window size change as well
signal.signal(signal.SIGWINCH, sigwinch_passthrough)

p.interact()