设计意图:初始化一次spawn对象,执行ssh后下发,一系列cmds。网上大部分时通过ssh [email protected] cmd的方法,这样的话,我就之需要通过for调用:
def SSH_COMMANDS(ip,user,passwd,command): try: ssh_pc = pexpect.spawn(‘ssh %[email protected]%s %s‘ % (user,ip,command),timeout=5,logfile=logfile) ... r=ssh_pc.read() print r except TIMEOUT,EOF: ssh_pc.close() ... for cmd in cmds: SSH_COMMANDS(ip,user,passwd,cmd)
但是,每次for都要生成spawn对象,所以,我的方法是:
def SSH_COMMANDS(ip,user,passwd,commands): try: ssh_pc = pexpect.spawn(‘ssh %[email protected]%s‘ % (user,ip),timeout=5,logfile=logfile) ... for command in commands: ssh_pc.expect(‘#‘) ssh_pc.sendline(command) r=ssh_pc.read() print r except TIMEOUT,EOF: ssh_pc.close() ... SSH_COMMANDS(ip,user,passwd,cmds)
我的code如下:
import pexpect import sys def SSH_COMMANDS(ip,user,passwd,commands): ip=str(ip) user=str(user) passwd=str(passwd) #logfile=file(‘%s_%s‘ % (ip,user),‘w‘) logfile=sys.stdout ssh_pc = pexpect.spawn(‘ssh %[email protected]%s‘ % (user,ip),timeout=5,logfile=logfile) try: match_tag = ssh_pc.expect([‘continue connecting (yes/no)?‘,‘password:‘],timeout=3) if match_tag==0: print ‘#‘*30 ssh_pc.sendline(‘yes‘) ssh_pc.expect(‘password:‘) ssh_pc.sendline(passwd) elif match_tag==1: print ‘=‘*30 ssh_pc.sendline(passwd) for cmd in commands: ssh_pc.expect([‘#‘,pexpect.TIMEOUT,pexpect.EOF]) ssh_pc.sendline(cmd) ssh_pc.expect([‘#‘,pexpect.TIMEOUT,pexpect.EOF]) ssh_pc.close #ssh_pc.sendline(‘exit‘) print ssh_pc.read() except pexpect.EOF: print ‘sub process abort unfortinately‘ ssh_pc.close except pexpect.TIMEOUT: print ‘expect patterns failed‘ ssh_pc.close SSH_COMMANDS(‘172.172.1.1‘,‘root‘,‘fortinet‘,[‘uname -a‘,‘hostname‘])
运行结果:
[email protected]‘s password: ==============================
fortinet
Welcome to Ubuntu 12.04.4 LTS (GNU/Linux 3.5.0-23-generic x86_64)
* Documentation: https://help.ubuntu.com/
System information as of Tue Oct 21 11:50:25 CST 2014
System load: 0.08 Users logged in: 2
Usage of /: 12.4% of 28.81GB IP address for eth0: 172.172.1.1
Memory usage: 5% IP address for eth1: 10.1.1.1
Swap usage: 0% IP address for eth2: 10.16.1.2
Processes: 218
Graph this data and manage this system at:
https://landscape.canonical.com/
175 packages can be updated.
118 updates are security updates.
New release ‘14.04.1 LTS‘ available.
Run ‘do-release-upgrade‘ to upgrade to it.
You have new mail.
Last login: Tue Oct 21 11:05:45 2014 from 172.172.4.1
[email protected]:~# uname -a
uname -a
Linux DEV-1-A 3.5.0-23-generic #35~precise1-Ubuntu SMP Fri Jan 25 17:13:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
[email protected]:~# hostname
hostname
DEV-1-A
[email protected]:~# expect patterns failed 这里匹配到pexpect.TIMEOUT分支。网上查了很多资料,也看了别人写的程序,他们是在初始化对象时,把cmd加到了pexpect.spawn的command参数,即:
ssh_pc = pexpect.spawn(‘ssh %[email protected]%s %s‘ % (user,ip,cmd),timeout=5,logfile=logfile) ,我这样试过,确实可以规避read()抛出的异常,然后把整个SSH_COMMANDS函数放到一个for循环也可以实现传递一个list类型的cmds。但是这相当于每次要初始化一个spawn类对象。而我,希望初始化一次spawn类对象,通过expect和sendline循环使用,下发list类型的cmds。
然而,当我取消注释下面一行后,TIMEOUT异常消失了。
ssh_pc.sendline(‘exit‘)
执行通过的code如下:
import pexpect import sys def SSH_COMMANDS(ip,user,passwd,commands): ip=str(ip) user=str(user) passwd=str(passwd) #logfile=file(‘%s_%s‘ % (ip,user),‘w‘) logfile=sys.stdout ssh_pc = pexpect.spawn(‘ssh %[email protected]%s‘ % (user,ip),timeout=5,logfile=logfile) try: match_tag = ssh_pc.expect([‘continue connecting (yes/no)?‘,‘password:‘],timeout=3) if match_tag==0: print ‘#‘*30 ssh_pc.sendline(‘yes‘) ssh_pc.expect(‘password:‘) ssh_pc.sendline(passwd) elif match_tag==1: print ‘=‘*30 ssh_pc.sendline(passwd) for cmd in commands: ssh_pc.expect([‘#‘,pexpect.TIMEOUT,pexpect.EOF]) ssh_pc.sendline(cmd) ssh_pc.expect([‘#‘,pexpect.TIMEOUT,pexpect.EOF]) ssh_pc.close ssh_pc.sendline(‘exit‘) print ssh_pc.read() except pexpect.EOF: print ‘sub process abort unfortinately‘ ssh_pc.close except pexpect.TIMEOUT: print ‘expect patterns failed‘ ssh_pc.close SSH_COMMANDS(‘172.172.1.1‘,‘root‘,‘fortinet‘,[‘uname -a‘,‘hostname‘])
执行结果:
[email protected]‘s password: ==============================
fortinet
Welcome to Ubuntu 12.04.4 LTS (GNU/Linux 3.5.0-23-generic x86_64)
* Documentation: https://help.ubuntu.com/
System information as of Tue Oct 21 12:50:53 CST 2014
System load: 0.0 Users logged in: 2
Usage of /: 12.4% of 28.81GB IP address for eth0: 172.172.1.1
Memory usage: 5% IP address for eth1: 10.1.1.1
Swap usage: 0% IP address for eth2: 10.16.1.2
Processes: 218
Graph this data and manage this system at:
https://landscape.canonical.com/
175 packages can be updated.
118 updates are security updates.
New release ‘14.04.1 LTS‘ available.
Run ‘do-release-upgrade‘ to upgrade to it.
You have new mail.
Last login: Tue Oct 21 11:50:25 2014 from 172.22.4.7
[email protected]:~# uname -a
uname -a
Linux DEV-1-A 3.5.0-23-generic #35~precise1-Ubuntu SMP Fri Jan 25 17:13:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
[email protected]:~# hostname
exit
hostname
DEV-1-A
[email protected]A:~# exit
logout
Connection to 172.172.1.1 closed.
hostname
DEV-1-A
[email protected]:~# exit
logout
Connection to 172.172.1.1 closed.
想不明白一个问题,我已经ssh_pc.read()前执行ssh_pc.close(),为什么一定要再发送个ssh_pc.sendline(‘exit‘)才能规避异常TIMEOUT。请明白的大神指点一下。谢谢。