http://d-up.org/man/2010/01/python-ssh/
最近写一个脚本,需要SSH到一个设备上,基于linux的,并在该设备上进入特权模式,这里用这样一样例子来演示,普通用户登录到ssh,然后切换root用户,这是会提示再次输入密码,就是这样一个效果。折腾半天,总算搞定了,把试过的各种方法给大家分享下。主要尝试了paramiko 以及 pexpect这两个库。
Paramiko之SSHClient()
起初用的Paramiko中的SSHClient()类来实现,连接到SSH并执行操作很简单:
#!/usr/bin/python
import paramiko
hostname= '192.168.73.137'
port = 22
username='man'
password='d-up.org'
if __name__=="__main__":
paramiko.util.log_to_file('paramiko.log')
s = paramiko.SSHClient()
s.load_system_host_keys()
s.connect(hostname,port,username,password)
stdin,stdout,stderr=s.exec_command('whoami')
ss=stdout.read()
print ss
stdin,stdout,stderr=s.exec_command('su root')
stdin,stdout,stderr=s.exec_command('rootpass) ##这里不能成功发送命令
……
……
s.close()
这时是用exec_command来执行命令,起初我以为字符串+回车,因此认为当su root 后直接发送密码过去便可以成功登录,后来发现这里的执行命令不是简单的发送字符串+回车,这样写是无法成功的,于是我查看了下SSHClient类,没有发现可以执行此类操作的函数。多次研究后不成功,只好放弃。
Pexpect之pxssh
Pexpect是一个很强大的库,可以用来创建子进程并与其通信。我找到它是因为它也包含一个ssh对象:pxssh,而且他有一个函数sendline(),看到这个函数就觉得这次应该成功了,查了下,这个函数的工作方法如同上面我想的那样,发送”command + \n”。因此很轻松的就实现了我需求的功能。实现所用代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pxssh #pxssh 位于pexpect中
try:
# 调用构造函数,创建一个 pxssh 类的对象.
s = pxssh.pxssh()
hostname = '192.168.73.126'
username = 'man'
password = 'd-up.org'
# 利用 pxssh 类的 login 方法进行 ssh 登录,原始 prompt 为'$' , '#'或'>',这个方法不用指定端口
s.login (hostname, username, password, original_prompt='[$#>]')
s.sendline ('whoami')
# 匹配 prompt
s.prompt()
# 将 prompt 前所有内容打印出,即命令 'whoami' 的执行结果.
print s.before
# 发送命令 ' ls -l '
p2='root_pass'
s.sendline ('su root') #此时不需要prompt,如果我们直接操作的话会看到提示输入密码
x=s.expect(['口令: ']) # 关键expect期待后面数组中的内容,并进行匹配,这里由于我使用的中文GUN Linux,所以我希望他匹配 提示中的口令两个字
if x==0: #0是 expect匹配数组中“口令”的位置,这里只有一个,所以是0
s.sendline(p2) # 匹配成功后发送的命令
s.prompt()
print s.before #这是就可以prompt了,因为su成功后有 #的提示符
print 'su ok'
s.sendline('whoami')
s.prompt()
print s.before #应该可以看到身份是root 模拟键盘提交密码成功!
# 退出 ssh session
s.sendline('exit')
s.logout()
except pxssh.ExceptionPxssh, e:
print "pxssh failed on login."
print str(e)
我开始测试代码的时候是用自己的系统做的测试,一切工作正常,但是后面发生意外了,当我去连接该设备的时候,出现了错误,pexpect库报错,现在我也没有找到原因,用多台设备进行测试均无法正常工作。E文不太好,最后没有解决。只好在回到paramiko身上,因为大家都说他很强大。
Paramiko之Transport
最后的实现方法,Transport类,这个类更加通用,说明是这样的(我就不翻译了,免得丢人):An SSH Transport attaches to a stream (usually a socket), negotiates an encrypted session, authenticates, and then creates stream tunnels, called Channels, across the session. Multiple channels can be multiplexed across a single session (and often are, in the case of port forwardings).
该类有send()方法,其工作原理更简单,直接发送字符串,回车还得自己补上,千万别忘记了,这个十分好用,代码很清晰,最终在那个设备上完成了任务。实现代码如下,大家看看应该也就明白了。
import paramiko
s = paramiko.Transport(('192.168.73.126', 22)) #创建对象
s.connect(username='man', password='d-up.org') #连接
chan = s.open_session() #得到session
chan.get_pty() #Request a pseudo-terminal from the server. 这两行实在翻译不好,大家自己看看吧
chan.invoke_shell() #Request an interactive shell session on this channel.
chan.send('su root\n') #逐行发送命令,如果进行的操作复杂,最好等上几秒,或者通过接受到的数据来进行判断,然后再执行后面的命令
chan.send('rootpass\n') #换行别忘记发
chan.send('whoami\n') #www.d-up.org/man python爱好者
print chan.recv(1024) # 可以看到切换用户成功了,大功告成!
2 条评论
小波温馨提示:注意劳逸结合,合理安排作息时间,晚饭时间快到了!祝您周末愉快!
最好加个time.sleep