Python Pexpect模块详解:从原理到SSH自动化实战

青禾
青禾
发布时间:2026-10-14 | 6人浏览过
原创

本文深入解析Python Pexpect模块,介绍其基于Expect原理的工作机制。详细讲解spawn、expect、send/sendline及interact等核心API的使用方法,包括参数匹配、异常处理及正则表达式应用。通过完整的SSH远程连接示例,展示如何利用Pexpect实现命令行程序的自动化交互与控制,适用于运维自动化与测试场景。

Pexpect简介

在深入探讨Pexpect之前,有必要先了解其前身Expect脚本语言。Expect由TCL语言开发,专为自动化人机交互式对话而设计,常用于处理ssh、ftp、telnet等需要命令行交互的程序。Pexpect则是Python语言对Expect功能的实现,允许开发者在Python环境中执行原本由Expect完成的任务。

Pexpect的基本工作流程主要包含三个核心步骤:

  1. 首先,调用spawn函数启动目标程序;
  2. 接着,使用expect方法等待目标程序在标准输出中打印的特定关键字;
  3. 最后,一旦检测到指定关键字,通过send或sendline方法向该程序发送字符串指令。

通常情况下,第一步仅需执行一次,而第二步和第三步会循环执行以完成整个任务流程。此外,Pexpect提供了丰富的其他方法,开发者可根据具体需求灵活选用。

Pexpect API

spawn类


class spawn(SpawnBase):
  '''This is the main class interface for Pexpect. Use this class to start
  and control child applications. '''

  # This is purely informational now - changing it has no effect
  use_native_pty_fork = use_native_pty_fork
  
	def __init__(self, command, args=[], timeout=30, maxread=2000,
           searchwindowsize=None, logfile=None, cwd=None, env=None,
           ignore_sighup=False, echo=True, preexec_fn=None,
           encoding=None, codec_errors='strict', dimensions=None,
           use_poll=False):

spawn()方法用于启动一个外部程序,并返回该程序的操作句柄。获取句柄后,即可通过该对象与子程序进行交互操作。


# 子程序退出时会引发pexpect.EOF异常,即如果捕捉到pexpect.EOF则说明子程序已退出
process = pexpect.spawn('ls -l')
process.expect(pexpect.EOF)
result = process.before.decode()
print(result)

需要注意的是,command参数不支持管道符、通配符或重定向符等特殊字符含义。在Linux系统中,若需使用这些符号的特殊功能,必须通过shell参数来运行程序。


# 示例一
process = pexpect.spawn('bash -c "ls -l | wc -l"')
process.expect(pexpect.EOF)

# 示例二
# 第一个参数为主程序,而args列表里的元素是主程序的参数
process = pexpect.spawn('bash', ['-c', 'ls -l | wc -l'])
process.expect(pexpect.EOF)

expect()方法

在通过spawn()启动程序并获得控制句柄后,即可使用expect()方法等待预设的关键字。关键字可以是字符串、正则表达式、EOF(文件结束)、TIMEOUT(超时)或上述类型的列表,用于匹配子程序的输出结果。若仅传入字符串等非列表类型,匹配成功返回0;若传入列表,则返回匹配成功的列表元素索引;若匹配失败,则会抛出异常。


process = pexpect.spawn('ls -l')
# 匹配expect字符
process.expect('expect')

当expect()成功匹配关键字后,系统会自动赋值给before、after和match三个变量,利用它们可以获取子程序的运行输出详情。

  • before:保存匹配到关键字之前,缓存中已有的所有数据。例如,若缓存了100个字符后匹配到关键字,before即为这100个字符(不含关键字本身)。
  • after:保存匹配到的关键字字符串。
  • match:保存匹配到的正则表达式对象实例。与after不同,after存储的是匹配到的具体字符串,而match存储的是正则表达式的匹配对象。

process = pexpect.spawn('ls -l')
process.expect('expect')
print(process.before.decode())
print(process.after.decode())
print(process.match)

若expect()执行过程中发生错误,before将保存截至错误发生前缓存中的所有数据,而after和match均为None。

若未匹配成功,expect()会抛出异常。开发者可以通过捕获该异常来防止错误信息在终端直接显示,从而优化用户体验。


process = pexpect.spawn('ls -l')
# 返回0表示匹配成功,返回1和2表示匹配到了异常
index = process.expect(['expect', pexpect.EOF, pexpect.TIMEOUT])
print(index)

send()/sendline()方法

sendline()与send()的主要区别在于,sendline()发送的字符串会自动附加回车符(newline)。


process = pexpect.spawn('nslookup')
process.expect('>')
process.sendline('www.baidu.com')
process.expect('>')
print(process.before.decode())
process.sendline('exit')

Pexpect还提供了众多其他辅助方法,此处不再赘述,详细用法建议参考官方文档。

interact()方法

interact()方法用于将终端控制权交还给用户(即把标准输入权交给用户)。默认情况下,Pexpect会接管所有的输入和输出;若需让用户介入完成部分交互工作,interact()便派上了用场。


# 让出控制权给用户
process.interact()
# 通过设置escape_character的值定义返回码,当用户输入此值后,会将控制权重新交给pexpect
process.interact(escape_character='\x1d', input_filter=None, output_filter=None)

应用示例

接下来,通过一个SSH连接远程服务器的示例,来实际体验Pexpect的使用方法。


#!/usr/bin/env python3.6
#-*- coding:utf-8 -*-

import pexpect

def main(server):
  command = 'ssh -p %s %s@%s' % (server['port'], server['username'], server['hostname'])
  process = pexpect.spawn(command, timeout=30)
  print(f'命令: {command}')
  expect_list = [
    'yes/no',
    'password:',
    pexpect.EOF,
    pexpect.TIMEOUT,
  ]
  index = process.expect(expect_list)
  print(f'匹配到: {index} => {expect_list[index]}')
  if index == 0: 
    process.sendline("yes")
    expect_list = [
      'password:',
      pexpect.EOF,
      pexpect.TIMEOUT,
    ]
    index = process.expect(expect_list)
    print(f'匹配到: {index} => {expect_list[index]}')
    if index == 0:
      process.sendline(server['password'])
      process.interact()
    else:
      print('EOF or TIMEOUT')
  elif index == 1:
    process.sendline(server['password'])
    process.interact()
  else:
    print('EOF or TIMEOUT')
  
if __name__ == '__main__':
  server = {
    'hostname': '192.168.1.100',
    'port': '22',
    'username': 'admin',
    'password': 'ABuklhsfnVyxI',
  }
  main(server)

以上就是Python Pexpect模块的使用详解,更多关于该模块的资料请关注本站其他相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表