使用python 实现自动登录ssh

介绍

本文介绍使用python 自动连ssh,并通过正则处理返回值。

通过这段代码,可以使一些繁杂的工作,变成比较简单以及自动化。

代码

#!/usr/bin/env python

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

global_pexpect_instance = None

# 当窗口大小有改变时
def sigwinch_passthrough(sig, data):
    # Set terminal size
    if 'TIOCGWINSZ' in dir(termios):
        TIOCGWINSZ = termios.TIOCGWINSZ
    else:
        TIOCGWINSZ = 1074295912
    s = struct.pack ("HHHH", 0, 0, 0, 0)
    a = struct.unpack ('HHHH', fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ , s))
    global global_pexpect_instance
    global_pexpect_instance.setwinsize(a[0],a[1])

# 处理返回值,并输入密码
def ssh_password(child,password,other=None):
    global base_path
    ssh_newkey = 'Are you sure you want to continue connecting'
    while True:
        step=[pexpect.TIMEOUT, ssh_newkey, '[pP]assword:.*', '.*[\$#] '];
        if other:
            step.append(other);
        i = child.expect(step,timeout=120)
        print "expect:"+step[i];
        if i == 0:
            print child.before,child.befor
            print child.before,child.after
            print 'Time out'
            return False;
        if i == 1:
            child.sendline('yes')
        if i == 2:
            child.sendline(password)
        if i == 3:
            print child.before,child.after
            return True;
    return True;

# 发送命令
def ssh_command(host, user, password, post_command=None):
    global global_pexpect_instance
    print 'ssh -l %s %s'%(user, host);
    child = pexpect.spawn('ssh -l %s %s'%(user, host))
    global_pexpect_instance = child
    signal.signal(signal.SIGWINCH, sigwinch_passthrough)
    if not ssh_password(child,password):
        return None;
    if post_command :
        child.sendline(post_command);
    return child;
# 等待返回,当非字符交互界面时用:如执行命令,等待结束
def ssh_wait(child,other=None):
    step=[pexpect.TIMEOUT,    '.*[\$#]'];
    if other:
        step.append(other);
    i = child.expect(step)
    print child.before
    print child.after

# 执行远程登录,如果有命令则直接返回,如果不是执行命令,则进入字符交互界面
def ssh(host,user,password,post_command=None):
    child=ssh_command(host,user,password,post_command)
    sigwinch_passthrough(None, None)
    if child==None:
        return
    if post_command==None:
        child.interact(chr(0x1e)) # ctrl+~
    else:
        ssh_wait(child)

解释

主要思路:

第一步: pexpect 包的spawn 执行ssh 并将用户名和地址填上

第二步:spawn会返回子进程的句柄,通过这个句柄,可以进行发送以及接收返回的字符串

第三步:使用 expect 函数,对返回进行正则匹配

第四步:

expect,会返回命中规则的下标,然后,可以对各种情况进行处理.

比如,在返回 '[pP]assword:.*' 时,发送密码

第五步:

最后,调用interact 进入字符交互界面。然后,就可以手动输入其他命令了。

总结

有了这套工具,可以实现快捷地登录服务器,或者是以另外一种鉴权方式登录服务器(如短信)

比如,我当前的使用是,快捷登录,比如输入 myssh cmky 就可以登录我的服务器了。

相当方便,如果使用linux 还可以和tmux 一同工作。

番外篇:与tmux 一同工作

我们将以上脚本保存为一个叫myssh 的可执行文件,并保存在可执行目录下

我们添加一个脚本,叫tssh :

echo $1
ifattach=0;
tmux -L `whoami` list-sessions
if [[ $? -ne 0 ]]; then
	echo "mytmux";
	ifattach=1;
	tmux -L `whoami` new -d
fi
tmux -L `whoami` neww -n $1 "myssh $1"

if [[ $ifattach -eq 1 ]]; then
	echo "attach"
	tmux -L `whoami` attach
fi

之所以添加 -L whoami 是为了避免在多用户下,公用tmux 而产生的问题。

保证每个用户一个tmux 服务

注意替换 myssh $1 为你自己的命令

humboldt Written by:

humboldt 的趣味程序园