[python] pexpect.spawn的对象child调用read()时触发TIMEOUT异常

设计意图:初始化一次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。请明白的大神指点一下。谢谢。

时间: 2024-10-13 08:23:42

[python] pexpect.spawn的对象child调用read()时触发TIMEOUT异常的相关文章

为对象添加一个释放时触发的block

有时我们需要在一个对象生命周期结束的时候触发一个操作,希望当该对象dealloc的时候调用一个外部指定的block,但又不希望直接hook dealloc方法,这样侵入性太强了.下面贴一段非常简单的实现方式,通过一个category给外部暴露一个block注入的接口,内部将该block封装到一个寄生对象中(Parasite),该寄生对象在dealoc的时候触发block调用,所有的寄生对象通过runtime的AssociatedObject机制与宿主共存亡,从而达到监控宿主生命周期的目的. 注意

python pexpect 学习与探索

pexpect是python交互模块,有两种使用方法,一种是函数:run另外一种是spawn类 1.pexpect  module 安装 pexpect属于第三方的,所以需要安装, 目前的版本是 3.3 下载地址 https://pypi.python.org/pypi/pexpect/ 安装步骤: tar -xzvf pexpect-3.3.tar.gz cd pexpect-3.3 python setup install (require root) 但是 这个安装需要root权限,如果没

python基础之面对对象

Python3 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程. 接下来我们先来简单的了解下面向对象的一些基本特征. 面向对象编程--Object Oriented Programming,简称OOP

python(pexpect)简单的自动ssh脚本

# vi ssh.py #!/usr/bin/python 按a或i进入编辑模式 import pexpect child=pexpect.spawn('ssh [email protected]') child.expect('password:') child.sendline('123456') child.interact() child.close() 按Esc键退出编辑模式 :wq(保存并退出) # python ssh.py 要自动退出登录在child.interact()前加ch

Python中的函数对象与闭包

函数在Python中是第一类对象,可以当做参数传递给其他函数,放在数据结构中,以及作为函数的返回结果. 下面的例子为接受另外一个函数作为输入并调用它 1 #foo.py 2 def callf(func): 3 return func() 使用上面的函数: 1 import foo 2 def helloworld(): 3 return 'Hello,World' 4 5 print foo.callf(helloworld) >>>‘Hello,World’ 2.把函数当做数据处理时

Python用subprocess的Popen来调用系统命令

当我们须要调用系统的命令的时候,最先考虑的os模块.用os.system()和os.popen()来进行操作.可是这两个命令过于简单,不能完毕一些复杂的操作,如给执行的命令提供输入或者读取命令的输出,推断该命令的执行状态,管理多个命令的并行等等.这时subprocess中的Popen命令就能有效的完毕我们须要的操作.在这里对Popen予以简介. 以下是一个非常easy的样例,来自Python的官网教程:http://docs.python.org/library/subprocess.html

正确理解Python函数是第一类对象

正确理解 Python函数,能够帮助我们更好地理解 Python 装饰器.匿名函数(lambda).函数式编程等高阶技术. 函数(Function)作为程序语言中不可或缺的一部分,太稀松平常了.但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性.那到底什么是第一类对象呢? 函数是对象 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性

python的变量,对象的内存地址以及参数传递过程

作为一个由c/c++转过来的菜鸟,刚接触Python的变量的时候很不适应,应为他的行为很像指针,void* ,不知道大家有没有这样的感觉.其实Python是以数据为本,变量可以理解为标签.作为c/c++的菜鸟,把跟踪变量地址的习惯带入Python,举个小例子说明Python的变量,对象,及参数传递. 1 '''例子1''' 2 x = 1 3 def fun(x): 4 x = 2 5 return None 6 7 fun(x) 8 print(x) 其实不打印也可以,我们用pycharm单步

一入python深似海--对象的属性

Python中一切皆是对象,每个对象都可以有多个属性.Python是如何管理这些属性呢?我们来探讨一下. 属性的__dict__系统 对象的属性包含两部分:类属性和对象属性.对象的属性可能来自于其类的定义,叫做类属性.类属性可能来自于类的定义自身,也可能来自父类.一个对象的属性还可能是该对象实例定义的,叫做对象属性. 对象的属性存储在对象的__dict__属性中.__dict__为一个字典,键为属性名,对应的值为属性本身.下面是一个例子. class bird(object): feather