Python的Pexpect模块详解

来源:互联网 发布:聪明坏处 知乎 编辑:程序博客网 时间:2024/05/23 00:41

对于存在交互过程的远程访问,如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 pexpectssh_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 ('.+')#只匹配一个.
ssh_client.expect ('.*')#什么都不匹配
    • 如果没有任何字符模式被匹配,将抛出超时异常,默认超时时间为30s
ssh_client.expect (['Permission denied', 'Terminal type', '[#\$] '], timeout=60)#超时时间60s
ssh_client.expect (['Permission denied', 'Terminal type', '[#\$] '], timeout=None)#永不超时
  • 子应用在每次expect()调用的前后,子应用输出的文本分别写入到before和after属性
ssh_client.before属性,包含子应用输出的文本,直到出现了期望的字符串
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