pexpect 应用示例

下面介绍两个通过 pexpect 实现自动化操作的示例,其中一个实现 FTP 协议的自动交互,另一个为 SSH 协议自动化操作,这些都是日常运维中经常遇到的场景。

实现一个自动化FTP操作

我们常用 FTP 协议实现自动化、集中式的文件备份,要求做到账号登录、文件上传与下载、退出等实现自动化操作,本示例使用 pexpect 模块的 spawnu() 方法执行 FTP 命令,通过 expect() 方法定义匹配的输出规则,sendline() 方法执行相关 FTP 交互命令等,详细源码如下:

pexpect/simple2.py
from __future__ import unicode_literals  # 使用unicode编码
import pexpect
import sys

child = pexpect.spawnu('ftp ftp.openbsd.org')  # 运行ftp命令
child.expect('(?i)name .*: ')  # (?i)表示后面的字符串正则匹配忽略大小写
child.sendline('anonymous')  # 输入ftp账号信息
child.expect('(?i)password')  # 匹配密码输入提示
child.sendline('pexpect@sourceforge.net')  # 输入ftp密码
child.expect('ftp> ')
child.sendline('bin')  # 启用二进制传输模式
child.expect('ftp> ')
child.sendline('get robots.txt')  # 下载robots.txt文件
child.expect('ftp> ')
sys.stdout.write(child.before)  # 输出匹配“ftp> ”之前的输入与输出
print("Escape character is '^]'.\n")
sys.stdout.write(child.after)
sys.stdout.flush()
# 调用interact()让出控制权,用户可以继续当前的会话手工控制子程序,默认输入“^]”字符跳出
child.interact()
child.sendline('bye')
child.close()

运行结果如下:

get robots.txt
local: robots.txt remote: robots.txt
227 Entering Passive Mode (129,128,5,191,197,243)
150 Opening BINARY mode data connection for 'robots.txt' (26 bytes).
226 Transfer complete.
26 bytes received in 3.29 secs (0.01 Kbytes/sec)
Escape character is '^]'.
ftp>  #调用interact()控制项让出,用户可以手工进行交互

远程文件自动打包并下载

在 Linux 系统集群运营当中,时常需要批量远程执行 Linux 命令,并且双向同步文件的操作。本示例通过使用 spawn() 方法执行 ssh、scp 命令的思路来实现,具体实现源码如下:

pexpect/simple3.py
import pexpect
import sys

ip = "192.168.1.21"  # 定义目标主机
user = "root"  # 目标主机用户
passwd = "H6DSY#*$df32"  # 目标主机密码
target_file = "/data/logs/nginx_access.log"  # 目标主机nginx日志文件
child = pexpect.spawn('/usr/bin/ssh', [user + '@' + ip])  # 运行ssh命令
fout = file('mylog.txt', 'w')  # 输入、输出日志写入mylog.txt文件
child.logfile = fout
try:
    child.expect('(?i)password')  # 匹配password字符串,(?i)表示不区别大小写
    child.sendline(passwd)
    child.expect('#')
    child.sendline('tar -czf /data/nginx_access.tar.gz ' + target_file)  # 打包nginx
    # 日志文件
    child.expect('#')
    print(child.before)
    child.sendline('exit')
    fout.close()
except EOF:  # 定义EOF异常处理
    print("expect EOF")
except TIMEOUT:  # 定义TIMEOUT异常处理
    print("expect TIMEOUT")

child = pexpect.spawn('/usr/bin/scp', [user + '@' + ip + ':/data/nginx_access.tar.gz',
                                       ' / home'])  #启动scp远程拷贝命令,实现将打包好的nginx日复制至本地/home目录
fout = file('mylog.txt', 'a')
child.logfile = fout
try:
    child.expect('(?i)password')
    child.sendline(passwd)
    child.expect(pexpect.EOF)  # 匹配缓冲区EOF(结尾),保证文件复制正常完成
except EOF:
    print("expect EOF")
except TIMEOUT:
    print("expect TIMEOUT")

参考提示