- 本书赞誉
- 前言
- 第一部分 基础篇
- 第1章 系统基础信息模块详解
- 第2章 业务服务监控详解
- 第3章 定制业务质量报表详解
- 第4章 Python 与系统安全
- 第二部分 高级篇
- 第5章 系统批量运维管理器 pexpect 详解
- 第6章 系统批量运维管理器 paramiko 详解
- 第7章 系统批量运维管理器Fabric详解
- 第8章 从零开发一个轻量级 WebServer
- 第9章 集中化管理平台 Ansible 详解
- 第10章 集中化管理平台 Saltstack 详解
- 第11章 统一网络控制器 Func 详解
- 第12章 Python 大数据应用详解
- 第三部分 案例篇
- 第13章 从零开始打造 B/S 自动化运维平台
- 第14章 打造 Linux 系统安全审计功能
- 第15章 构建分布式质量监控平台
- 第16章 构建桌面版 C/S 自动化运维平台
5.2 pexpect 的核心组件
下面介绍pexpect的几个核心组件包括spawn类、run函数及派生类pxssh等的定义及使用方法。
5.2.1 spawn类
spawn是pexpect的主要类接口,功能是启动和控制子应用程序,以下是它的构造函数定义:
class pexpect.spawn(command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None, ignore_sighup=True)
其中command参数可以是任意已知的系统命令,比如:
child = pexpect.spawn('/usr/bin/ftp') #启动ftp客户端命令 child = pexpect.spawn('/usr/bin/ssh user@example.com') #启动ssh远程连接命令 child = pexpect.spawn('ls -latr /tmp') #运行ls显示/tmp目录内容命令
当子程序需要参数时,还可以使用Python列表来代替参数项,如:
child = pexpect.spawn ('/usr/bin/ftp', []) child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com']) child = pexpect.spawn ('ls', ['-latr', '/tmp'])
参数timeout为等待结果的超时时间;参数maxread为pexpect从终端控制台一次读取的最大字节数,searchwindowsize参数为匹配缓冲区字符串的位置,默认是从开始位置匹配。
需要注意的是,pexpect不会解析shell命令当中的元字符,包括重定向“>”、管道“|”或通配符“*”,当然,我们可以通过一个技巧来解决这个问题,将存在这三个特殊元字符的命令作为/bin/bash的参数进行调用,例如:
child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"') child.expect(pexpect.EOF)
我们可以通过将命令的参数以Python列表的形式进行替换,从而使我们的语法变成更加清晰,下面的代码等价于上面的。
shell_cmd = 'ls -l | grep LOG > logs.txt' child = pexpect.spawn('/bin/bash', ['-c', shell_cmd]) child.expect(pexpect.EOF)
有时候调试代码时,希望获取pexpect的输入与输出信息,以便了解匹配的情况。pexpect提供了两种途径,一种为写到日志文件,另一种为输出到标准输出。写到日志文件的实现方法如下:
child = pexpect.spawn('some_command') fout = file('mylog.txt','w') child.logfile = fout
输出到标准输出的方法如下:
child = pexpect.spawn('some_command') child.logfile = sys.stdout
下面为一个完整的示例,实现远程SSH登录,登录成功后显示/home目录文件清单,并通过日志文件记录所有的输入与输出。
import pexpect import sys child = pexpect.spawn('ssh root@192.168.1.21') fout = file('mylog.txt','w') child.logfile = fout #child.logfile = sys.stdout child.expect("password:") child.sendline("U3497DT32t") child.expect('#') child.sendline('ls /home') child.expect('#')
以下为mylog.txt日志内容,可以看到pexpect产生的全部输入与输出信息。
# cat mylog.txt root@192.168.1.21's password: U3497DT32t Last login: Tue Jan 7 23:05:30 2014 from 192.168.1.20 [root@SN2013-08-021 ~]# ls /home ls /home cc.py poster-0.8.1 tarfile.tar.gz zipfile.zip default.tar.gz poster-0.8.1.tar.gz test.sh dev pypa-setuptools-c508be8585ab zipfile1.zip
(1)expect方法
expect定义了一个子程序输出的匹配规则。
方法定义:expect(pattern,timeout=–1,searchwindowsize=–1)
其中,参数pattern表示字符串、pexpect.EOF(指向缓冲区尾部,无匹配项)、pexpect.TIMEOUT(匹配等待超时)、正则表达式或者前面四种类型组成的列表(List),当pattern为一个列表时,且不止一个表列元素被匹配,则返回的结果是子程序输出最先出现的那个元素,或者是列表最左边的元素(最小索引ID),如:
import pexpect child = pexpect.spawn("echo 'foobar'") print child.expect(['bar', 'foo', 'foobar']) 输出:1,即'foo'被匹配
参数timeout指定等待匹配结果的超时时间,单位为秒。当超时被触发时,expect将匹配到pexpect.TIMEOUT;参数searchwindowsize为匹配缓冲区字符串的位置,默认是从开始位置匹配。
当pexpect.EOF、pexpect.TIMEOUT作为expect的列表参数时,匹配时将返回所处列表中的索引ID,例如:
index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT]) if index == 0: do_something elif index == 1: do_something_else elif index == 2: do_some_other_thing elif index == 3: do_something_completely_different
以上代码等价于
try: index = p.expect(['good', 'bad']) if index == 0: do_something elif index == 1: do_something_else except EOF: do_some_other_thing except TIMEOUT: do_something_completely_different
expect方法有两个非常棒的成员:before与after。before成员保存了最近匹配成功之前的内容,after成员保存了最近匹配成功之后的内容。例如:
import pexpect import sys child = pexpect.spawn('ssh root@192.168.1.21') fout = file('mylog.txt','w') child.logfile = fout child.expect(["password:"]) child.sendline("980405") print "before:"+child.before print "after:"+child.after
运行结果如下:
before:root@192.168.1.21's after:password:
(2)read相关方法
下面这些输入方法的作用都是向子程序发送响应命令,可以理解成代替了我们的标准输入键盘。
send(self, s) 发送命令,不回车 sendline(self, s='') 发送命令,回车 sendcontrol(self, char) 发送控制字符,如child.sendcontrol('c')等价于”ctrl+c” sendeof 发送eof
5.2.2 run函数
run是使用pexpect进行封装的调用外部命令的函数,类似于os.system或os.popen方法,不同的是,使用run可以同时获得命令的输出结果及命令的退出状态,函数定义:pexpect.run(command,timeout=–1,withexitstatus=False,events=None,extra_args=None,logfile=None,cwd=None,env=None)。
参数command可以是系统已知的任意命令,如没有写绝对路径时将会尝试搜索命令的路径,events是一个字典,定义了expect及sendline方法的对应关系,spawn方式的例子如下:
from pexpect import * child = spawn('scp foo user@example.com:.') child.expect('(?i)password') child.sendline(mypassword)
使用run函数实现如下,是不是更加简洁、精炼了?
from pexpect import * run('scp foo user@example.com:.', events={'(?i)password': mypassword})
5.2.3 pxssh类
pxssh是pexpect的派生类,针对在ssh会话操作上再做一层封装,提供与基类更加直接的操作方法。
pxssh类定义:
class pexpect.pxssh.pxssh(timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None)
pxssh常用的三个方法如下:
login建立ssh连接;
logout断开连接;
prompt等待系统提示符,用于等待命令执行结束。
下面使用pxssh类实现一个ssh连接远程主机并执行命令的示例。首先使用login方法与远程主机建立连接,再通过sendline方法发送执行的命令,prompt方法等待命令执行结束且出现系统提示符,最后使用logout方法断开连接。
【/home/test/pexpect/simple1.py】
import pxssh import getpass try: s = pxssh.pxssh #创建pxssh对象s hostname = raw_input('hostname: ') username = raw_input('username: ') password = getpass.getpass('please input password: ') #接收密码输入 s.login (hostname, username, password) #建立ssh连接 s.sendline ('uptime') # 运行uptime命令 s.prompt # 匹配系统提示符 print s.before # 打印出现系统提示符前的命令输出 s.sendline ('ls -l') s.prompt print s.before s.sendline ('df') s.prompt print s.before s.logout #断开ssh连接 except pxssh.ExceptionPxssh, e: print "pxssh failed on login." print str(e)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论