对于存在交互过程的远程访问,如ssh, ftp, mencoder, passwd等,通过Pexpect模块可以根据应用的输出控制交互过程,从而提高容错性。
Pexpect模块首先通过生成子应用以代理交互应用,这样就可以通过检测子应用的模式匹配情况以响应交互应用的输出。
作为Don Libes的Expect实现之一,Pexpect模块是一个纯Python实现。
Python也有其他的类Expect模块,但是这些模块往往依赖于TCL和Expect扩展模块,或编译时依赖于C扩展模块。而Pexpect模块除了基于Python标准库中的pty模块之外,完全独立。从Pexpect 4.0开始,Pexpect模块可运行于Windows系统和POSIX系统。当然,由于pexpect.spawn()和pexpect.run()依赖于Python标准库中的pty模块,而pty模块只在POSIX系统中存在,所以Windows系统上的功能有限。
1. Pexpect模块的安装:
Python 3.3或Python 2.7以上
pip install pexpect
2. Pexpect模块的组成:
1) pexpect.run()函数
该函数执行一个命令并返回命令的结果,可用以替代os.system()。
pexpect.run('ls -la')
2) pexpect.SpawnBase类
抽象基类,永远不能直接实例化。其中定义的主要属性和方法如下:
- self.before = None
- self.after = None
- def expect(self, pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw)
3) pexpect.spawn类
继承自SpawnBase类。用法如下:
child = pexpect.spawn('/usr/bin/ftp')
child = pexpect.spawn('/usr/bin/ssh user@example.com')
child = pexpect.spawn('ls -latr /tmp')
child = pexpect.spawn('/usr/bin/ftp', [])
child = pexpect.spawn('/usr/bin/ssh', ['user@example.com'])
child = pexpect.spawn('ls', ['-latr', '/tmp'])
仔细观察上述语句,给出了两种创建子应用的方式。
再如:
child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
child.expect(pexpect.EOF)
等价于
child = pexpect.spawn('/bin/bash', ['-c', 'ls -l | grep LOG > logs.txt'])
child.expect(pexpect.EOF)
- expect()方法
下面就可以对子应用调用方法,检测交互过程的输出并进行相应的输入。
import pexpect
ssh_client = pexpect.spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2211 user@host")
ssh_client.expect(...)
expect()方法是最常用的方法之一,等待子应用返回指定的字符串。expect()方法的特性如下:
- Pexpect一次从子应用中读取一个字符,所以在字符模式中,$符号不能匹配为行末或字符串结尾。
- 要匹配行末使用'\r\n',这适合Windows系统和POSIX系统。
- expect()返回被匹配的字符模式的序号,从0开始
- 最少匹配原则
ssh_client.expect ('.*')#什么都不匹配
- 如果没有任何字符模式被匹配,将抛出超时异常,默认超时时间为30s
ssh_client.expect (['Permission denied', 'Terminal type', '[#\$] '], timeout=None)#永不超时
- 子应用在每次expect()调用的前后,子应用输出的文本分别写入到before和after属性
ssh_client.after属性,包含匹配了的字符串
- send()
写入一个字符串到子应用
- sendline()
- logfile属性
ssh_client.logfile = sys.stdout#将日志输出到控制台
3) pexpect.EOF类
默认遇到子应用的EOF,expect()会抛出异常
4) pexpect.TIMEOUT类
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()
参考链接:
https://pypi.python.org/pypi/pexpect/
https://pexpect.readthedocs.io/en/stable/
https://pexpect.readthedocs.io/en/stable/api/index.html
https://github.com/pexpect/pexpect