系统批量运维管理器pexpect详解
一、pexpect介绍
pexpect可以理解成Linux下的expect的Python封装,通过pexpect我们可以实现对ssh、ftp、passwd、telnet等命令进行自动交互,而无需人工干涉来达到自动化的目的。比如我们可以模拟一个FTP登陆时的所有交互,包括输入主机地址、用户名、密码、上传文件等,待出现异常我们还可以进行尝试自动处理。
pexpect官网地址:https://pexpect.readthedocs.io/en/stable/
https://pypi.org/project/pexpect/
二、pexpect的安装
mac os安装
pip3 install pexpect
CentOS 安装
[root@localhost ~]# pip3 install pexpect
Collecting pexpect
Downloading https://files.pythonhosted.org/packages/89/e6/b5a1de8b0cc4e07ca1b305a4fcc3f9806025c1b651ea302646341222f88b/pexpect-4.6.0-py2.py3-none-any.whl (57kB)
% |████████████████████████████████| 61kB 128kB/s
Collecting ptyprocess>=0.5 (from pexpect)
Downloading https://files.pythonhosted.org/packages/ff/4e/fa4a73ccfefe2b37d7b6898329e7dbcd1ac846ba3a3b26b294a78a3eb997/ptyprocess-0.5.2-py2.py3-none-any.whl
Installing collected packages: ptyprocess, pexpect
Successfully installed pexpect-4.6. ptyprocess-0.5.
三、pexpect的核心组件
spawn类
spawn是pexpect的主要类接口,功能是启动和控制子应用程序,以下是它的构造函数定义:
class pexpect.spawn(command, args=[], timeout=, maxread=, 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 = open('mylog.txt','wb')
child.logfile = fout
输出到标准输出的方法如下:
# In Python :
child = pexpect.spawn('some_command')
child.logfile = sys.stdout # In Python , we'll use the ``encoding`` argument to decode data
# from the subprocess and handle it as unicode:
child = pexpect.spawn('some_command', encoding='utf-8')
child.logfile = sys.stdout
logfile_read和logfile_send成员可用于分别记录来自子项的输入和发送给子项的输出。有时你不想看到你给孩子写的所有内容。你只想记录孩子送回的东西。例如:
child = pexpect.spawn('some_command')
child.logfile_read = sys.stdout
如果您使用的是Python 3,则需要在上面的代码中传递编码。
要单独记录发送给子级的输出使用logfile_send:
child.logfile_send = fout
注意:如果你想获得孩子的退出状态,你必须调用close()方法。孩子的出口或信号状态将存储在self.exitstatus或self.signalstatus中。如果孩子正常退出,exitstatus将存储退出返回码,signalstatus将为None。如果孩子被信号异常终止,那么signalstatus将存储信号值,exitstatus将为None:
child = pexpect.spawn('some_command')
child.close()
print(child.exitstatus, child.signalstatus)
更多细节,可以读取存储由os.waitpid返回的状态的self.status成员。你可以使用os.WIFEXITED/os.WEXITSTATUS 或 os.WIFSIGNALED/os.TERMSIG来解释它。
下面为一个完整的示例,实现远程SSH登录,登录成功后显示/usr/local/src/目录文件清单,并通过日志文件记录所有的输入与输出。
import pexpect
import sys child = pexpect.spawn('ssh root@192.168.56.132')
fout = open('mylog.txt',mode='wb')
child.logfile = fout
#child.logfile = sys.stdout child.expect("(yes/no)?")
child.sendline("yes")
child.expect("password:")
child.sendline("")
child.expect('#')
child.sendline('/bin/ls /usr/local/src/')
child.expect("#")
以下为mylog.txt日志内容,可以看到pexpect产生的全部输入与输出信息。
[root@localhost ~]# cat mylog.txt
yes
yes
root@192.168.56.132's password: 1234567 Last login: Sat Jun :: from 192.168.56.131
[root@localhost ~]# /bin/ls /usr/local/src/
/bin/ls /usr/local/src/
Python-3.6. Python-3.6..tgz
expect方法
expect定义了一个子程序输出的匹配规则。
方法定义:expect
(pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw)
其中,参数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 == :
do_something()
elif index == :
do_something_else()
elif index == :
do_some_other_thing()
elif index == :
do_something_completely_different()
以上代码等价于
try:
index = p.expect(['good', 'bad'])
if index == :
do_something()
elif index == :
do_something_else()
except EOF:
do_some_other_thing()
except TIMEOUT:
do_something_completely_different()
expect方法有两个非常棒的成员:befoe与。before成员保存了最近匹配成功之前的内容,affer成员保存了最近匹配成功之后的内容。例如:
import pexpect child = pexpect.spawn('ssh root@192.168.56.132',encoding='utf-8')
fout = open('mylog.txt',mode='w')
child.logfile = fout child.expect("(yes/no)?")
child.sendline("yes") child.expect(['password:'])
child.sendline("")
print("before:"+child.before)
print("after:"+child.after)
运行结果如下:
[root@localhost ~]# python3 simple2.py
before:yes
root@192.168.56.132's
after:password:
read相关方法
下面这些输入方法的作用都是向子程序发送响应命令,可以理解成代替了我们的标准输入键盘。
send(self,s) 发送命令,不回车
sendline(self, s='') 发送命令,回车
sendcontrol(self, char) 发送控制字符,如child.sendcontrol('c')等价于"ctrl+c"
sendof() 发送eof
四、run函数
run是使用pexpect进行封装的调用外部命令的函数,类似于os.system或os.popen方法,不同的是使用run()可以同时获得命令的输出结果及命令的退出状态,函数定义:
pexpect.run(command, timeout=, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None, **kwargs)。
参数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})
pxssh类
该类将pexpect.spawn扩展为专门设置SSH连接。增加了登录,注销和期望的shell提示的方法。它执行各种棘手的事情来处理SSH登录过程中的许多情况。例如,如果会话是您第一次登录,则pxssh会自动接收远程证书;或者你有公钥认证设置,则pxssh不会等待密码提示。
pxssh使用shell提示符来同步来自远程主机的输出。为了使它更健壮,它将shell提示设置为比$或#更独特的东西。这应该适用于大多数Borne/Bash or Csh 风格的 shell。
pxssh类定义:
classpexpect.pxssh.
pxssh
(timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None, ignore_sighup=True, echo=True, options={}, encoding=None, codec_errors='strict', debug_command_string=False)
pxssh常用的三个方法如下:
- login()建立ssh连接;
- logout()断开连接;
- prompt()等待系统提示符,用于等待命令执行结束。
下面使用pxssh类实现一个ssh连接远程主机并执行命令的示例。首先使用login()方法与远程主机建立连接,再通过sendline()方法发送执行的命令,prompt()方法等待命令执行结束且出现系统提示符,最后使用logout()方法断开连接。
from pexpect import pxssh
import getpass
try:
s = pxssh.pxssh() #创建pxssh对象s
hostname = raw_input('hostname: ')
username = raw_input('username: ')
password = getpass.getpass('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 as e:
print("pxssh failed on login.")
print(e)
五、pexpect应用实例
远程文件自动打包并下载
import pexpect
import sys ip='192.168.56.132' #定义目标主机
user='root' #目标主机用户
passwd='' #目标主机密码
target_file='/data/logs/nginx_access.log' #目标主机nginx日志文件 child = pexpect.spawn('/usr/bin/ssh', [user+'@'+ip],encoding='utf-8') #运行ssh命令
fout = open('mylog.txt','w') #输入、输出日志写入mylog.txt文件
child.logfile = fout try:
child.expect('(?i)password') #匹配password字符串,(?i)表示不区别大小写
child.sendline(passwd)
child.expect('#')
child.sendline('tar -zcPf /data/nginx_access.tar.gz ' +target_file) #打包nginx日志文件
child.expect('#')
print(child.before)
child.sendline('exit')
fout.close()
except EOFError: #定义EOF异常处理
print('expect EOF')
except TimeoutError: #定义timeout异常处理
print('expect timeout') child = pexpect.spawn('/usr/bin/scp', [user+'@'+ip+':/data/nginx_access.tar.gz','/home'],encoding='utf-8') #启动scp远程拷贝命令,实现将打包好的nginx日志复制到本地/home目录下
fout = open('mylog.txt','a')
child.logfile = fout
try:
child.expect('(?i)password')
child.sendline(passwd)
child.expect(pexpect.EOF) #匹配缓冲区EOF(结尾),保证文件复制正常完成
except EOFError:
print('expect EOF')
except TimeoutError:
print('expect timeout')
系统批量运维管理器pexpect详解的更多相关文章
- 系统批量运维管理器Fabric详解
系统批量运维管理器Fabric详解 Fabrici 是基于python现实的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包 ...
- 系统批量运维管理器paramiko详解
一.paramiko介绍 paramiko是基于Python实现的SSH2远程安全连接,支持认证及密钥方式.可以实现远程命令执行.文件传输.中间SSH代理等功能,相对于Pexpect,封装的层次更高, ...
- 系统批量运维管理器pexpect的使用
# pip install pexpect 或 # easy_install pexpect 1 #!/usr/bin/env python 2 import pexpect 3 child = pe ...
- GridBagLayout布局管理器应用详解
http://www.cnblogs.com/kungfupanda/p/7220217.html GridBagLayout布局管理器应用详解 很多情况下,我们已经不需要通过编写代码来实现一个应用程 ...
- PHPFastCGI进程管理器PHP-FPM详解
PHP-FPM是一个PHPFastCGI进程管理器,是只用于PHP的. PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中.必须将它patch到你的PH ...
- JAVA中GridBagLayout布局管理器应用详解
很多情况下,我们已经不需要通过编写代码来实现一个应用程序的图形界面,而是通过强大的IDE工具通过拖拽辅以简单的事件处理代码即可很轻松的完成.但是我们不得不面对这样操作存在的一些问题,有时候我们希望能够 ...
- 运维监控---企业级Zabbix详解_【all】
基础LNMP环境搭建 Linux 下LNMP环境搭建 下载Zabbix 链接:https://pan.baidu.com/s/1n36esVyYAKstwnFopbV2sg 密码:izll 创建zab ...
- 8.python 系统批量运维管理器之pexpect模块
小插曲 前几节讲了paramiko模块,但是pexpect模块的功能几乎跟paramiko一样,先来分析一下: 1.各自介绍 pexpect是一个通过启动子程序,使用正则表达式对程序输出做出特定响应, ...
- Python3自动化运维之Fabric模版详解
一.概要 Fabric是基于Python(2.7,3.4+以上版本)实现的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包括 ...
随机推荐
- C# 后台线程更新UI控件
/********************************************************************************* * C# 后台线程更新UI控件 * ...
- C#修改注册表
某次需要使用C#对注册表进行操作,不过却发现没有权限,研究了以下发现是当前系统用户的问题.除非当前系统用户是Administrator,否则就会给你抛出一个异常.后来在网上发现了一个方法,原来C#也可 ...
- opencrud graphql 数据操作指南
opencrud 是社区团队提出,同时prisma框架就是按照这个标准设计的,里面包含了对于graphql 数据 操作的最佳实践,目前还在完善中,但是设计以及指南覆盖的功能还是比较全的,如果用过 pr ...
- yarn workspaces基本试用
初始化项目 yarn init -y 添加workspaces 支持 修改package.json { "name": "second", "vers ...
- Linux之 linux7防火墙基本使用及详解
1.firewalld的基本使用 启动: systemctl start firewalld 查看状态: systemctl status firewalld 停止: systemctl disab ...
- SpringCloud初体验:前言
体验了一天 SpringCloud 后发现,人们所讲的微服务架构不是一门技术,而是一种风格. 感觉确实可以这么认同,因为一套 SpringCloud 玩下来(未深入.未完整「链路追踪.动态刷新配置…… ...
- 【linux】centos6.5搭建svn
1.检查是否已安装 rpm -qa subversion 如果要卸载旧版本: yum remove subversion 2.安装 yum install subversion PS:yum inst ...
- Linux Namespace
转载请注明出处,并保留以上所有对文章内容.图片.表格的来源的描述. 一.Linux Namespace Linux Namespace是Linux提供的一种OS-level virtualizatio ...
- Educational Codeforces Round 37-G.List Of Integers题解
一.题目 二.题目链接 http://codeforces.com/contest/920/problem/G 三.题意 给定一个$t$,表示有t次查询.每次查询给定一个$x$, $p$, $k$,需 ...
- Custom Exception in ASP.NET Web API 2 with Custom HttpResponse Message
A benefit of using ASP.NET Web API is that it can be consumed by any client with the capability of m ...