Python pexpect模块及shell脚本except原理解析


Posted in Python onAugust 03, 2020

expect脚本

expect是什么

expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了,expect就是一套用来实现自动交互功能的软件。

在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行

由于在linux中的一些命令不太适合于脚本的自动化运行,比如fdisk,telnet,ftp连接下载等,所以必须使用except来解决交换问题。

except基础

包含以下四个命令

命令 作用
send 用于向进程发送字符串
except 从进程接收字符串
spwan 启动新进程
interact 允许用户交互
  • send命令接收一个字符串参数,并将该参数发送到进程。
  • expect命令和send命令相反,expect通常用来等待一个进程的反馈,我们根据进程的反馈,再发送对应的交互命令。
  • spawn命令用来启动新的进程,spawn后的send和expect命令都是和使用spawn打开的进程进行交互。
  • interact命令用的其实不是很多,一般情况下使用spawn、send和expect命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。比如我们使用spawn、send和expect命令完成了ftp登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在ftp命令行状态,以便手动的执行后续命令,此时使用interact命令就可以很好的完成这个任务。

代码举例

#!/usr/bin/expect

set timeout 30
set host "101.200.241.109"
set username "root"
set password "123456"

spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact

这是一段非常简单代码,演示了基本用法

#!/usr/bin/expect:使用expect来解释该脚本;

set timeout 30:设置超时时间,单位为秒,默认情况下是10秒;

set host "101.200.241.109":设置变量;

spawn ssh $username@$host:spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。它主要的功能是给ssh运行进程加个壳,用来传递交互指令;

expect "password":这里的expect也是expect的一个内部命令,这个命令的意思是判断上次输出结果里是否包含“password”的字符串,如果有则立即返回;否则就等待一段时间后返回,这里等待时长就是前面设置的30秒;

send "$password\r":当匹配到对应的输出结果时,就发送密码到打开的ssh进程,执行交互动作;

interact:执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。

这就是对上述这段简单简单脚本的分析,在上述的示例中,涉及到expect中一个非常重要的概念——模式-动作;即上述expect "password" {send "$password\r"}这句代码表达出来的含义。

模式-动作

结合着expect "password" {send "$password\r"}这句代码来说说“模式-动作”。简单的说就是匹配到一个模式,就执行对应的动作;匹配到password字符串,就输入密码

如下所示:

expect {
  "password" {
    send "$password\r"
    exp_continue
  }
  eof
  {
    send "eof"
  }
}

其中exp_continue表示循环式匹配,通常匹配之后都会退出语句,但如果有exp_continue则可以不断循环匹配,输入多条命令,简化写法。

传参

很多时候,我们需要传递参数到脚本中,现在通过下面这段代码来看看如何在expect中使用参数:

#!/usr/bin/expect

if {$argc < 3} {
  puts "Usage:cmd <host> <username> <password>"
  exit 1
}

set timeout -1
set host [lindex $argv 0] 
set username [lindex $argv 1]
set password [lindex $argv 2]

spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact

在expect中,\$argc表示参数个数,而参数值存放在$argv中,比如取第一个参数就是[lindex $argv 0],以此类推。

FTP下载expect脚本

使用yum安装expect

yum install expect

按照如下编写expect脚本

#!/usr/bin/expect -f 
set ip [lindex $argv 0]                           #脚本的第一个参数,远程主机的IP地址
set file [lindex $argv 1]                          #脚本的第二个参数,指定下载的文件名
set timeout 10                                #设置超时时间10秒
spawn ftp $ip                                 #运行ftp $ip命令
expect "Name*"                               #如果出现Name字符
send "anonymous \r"                           #则输入anoymous(匿名用户)并回车
expect "Password:*"                           #如果出现Password字符
send "\r"                                     #则仅输入回车
expect "ftp>*"                                 #如果出现ftp>字符
send "get $file\r"                               #则发送get $file命令
expect {
  "*Failed*" { send_user " Download failed\r";send "quit\r"}  #如果返回的字符串有Failed,则说明下载失败,send_user回显信息 Download failed 
  "*send*" { send_user " Download ok\r";send "quit\r"} #如果返回的字符串有send,则说明下载失败,send_user回显信息 Download ok
  }
expect eof  #结束循环匹配

给脚本加上可执行权限chmod +x expect_ftp_auto.exp

pexpect模块

pexpect可以理解为linux下的expect的python封装,通过pexpect可以实现ssh,ftp,passwd,telnet等命令的进行自动交互

安装pip install pexpect

简单实现ssh自动登录的示例如下:

import pexpect
child = pexpect.spwan('scp foo user#expample.com:.')  #spwan启动scp程序
child.expect('Password:')          #expect方法等待子程序产生的输出,判断是否匹配定义的字符串
                                            #‘Password:'
child.sendline(mypassword)       #匹配后则发送密码进行回应

核心组件

spawn类

spawn是pexpect的主要入口,功能是启动和控制子应用程序,以下是它的构造函数

class pexpect.spwan(command,args=[],timeout=30,maxread=2000,searchwindowsize=None,logfile=None,cwd=None,env=None,ignore_sighup=True)

其中,command参数可以是任意已知的系统命令,比如

child=pexpect.spawn('user/bin/ftp')

当子程序需要参数的时候,还可以使用python列表来代替参数,如

child = pexpect.spwan('user/bin/ssh user@example.com')

参数timeout为等待结果的超时时间,maxread为从终端控制台一次读取的最大字节数,searchwindowsize参数为匹配的缓冲区字符串的位置,默认是从开始位置匹配

需要注意的是,pexpext不会解析shell命令中的元字符,包括重定向> 管道|或者通配符,此时可以将三个特殊元字符的命令作为/bin/bash的参数进行调用

child =expect.spwan('/bin/bash -c "ls -l | grep LOG> logs.txt"')
child.expect(pexpect.EOF)

可以通过将命令的参数以PYTHON列表的方式进行替换,从而使得语法更加清晰,下面的代码等同于上面的代码

shell_cmd='ls -l | grep LOG >logs.txt'
child=pexpext.spwan('/bin/bash',['-c,shell_cmd])
child.expect(pexpect.EOF)

在调试代码时,希望获取pexpect的输入与输出信息,以便了解匹配的情况,一种时写到日志中,另一种时输出到标准输出

写到日志中

chidl-pexpect.spwan('some_command')
fout=file('mylog.txt,'w')
child.logfile=fout

输出到标准输出的方法

child=pexpect.swpan('some_command')
chuld.logfile=sys.stdout

以下为SSH远程登录举例,登录成功后显示/home目录的文件并且记录输入与输出

import pexpect
import sys

child=pexpect.spawn('ssh root@172.31.208.129')
fout=open('mylog.txt','w')
child.logfile=fout
#child.logfile=sys.stdout

child.expect('password:')
child.sendline('abc@123')
child.expect('#')
child.sendline('ls /home')
child.expect('#')

expect方法

expect定义了子程序输出的匹配规则

方法定义:expect(pattern,timeout=-1,searchwindowsize=-1)

其中,参数pattern表示字符串,pexpext.EOF(指向缓冲区,无匹配项)、pexpect,TIMEOUT(匹配等待超时),正则表达式或者列表

参数timeout指定了等待匹配结果的超时时间,单位为秒,当超时被触发的时候,expect将匹配到pexpext.TIMEOUT,参数searchwindowsize为匹配的缓冲字符串的位置,默认时从开始的位置匹配

read相关方法

下面的的方法作用都是向子程序发送响应命令

send(self,s) #发送命令,不回车
sendline(self,s=' '),#发送命令,回车
snedcontrol(self.char) #发送控制字符
sendeof() #发送eof

run函数

run时使用pexpext进行封装的调用外部命令的的函数

from pexpect import *
run('scp foo user@example.com:.',events={'(?i)password':mypassword])

pxssh类

针对ssh会话操作上再做一次封装

class pexpext.pxssh.pxssh(timeout=30,maxread=2000,searchwindwosize=None,logfile=None,cwd=None,env=None)

常用方法

  • login()建立ssh连接
  • logout() 断开连接
  • promp()等待系统提示符,用于等待命令执行结束
import pxssh
import getpass
try:
  s = 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()
except pxssh.ExceptionPxssh, e:
  print "pxssh failed on login."
  print str(e)

FTP自动操作

实现自动交互登录FTP操作

import pexpect
import sys

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中类的定义、继承及使用对象实例详解
Apr 30 Python
asyncio 的 coroutine对象 与 Future对象使用指南
Sep 11 Python
Python探索之SocketServer详解
Oct 28 Python
python对excel文档去重及求和的实例
Apr 18 Python
python去除拼音声调字母,替换为字母的方法
Nov 28 Python
python3爬虫获取html内容及各属性值的方法
Dec 17 Python
详解用python写一个抽奖程序
May 10 Python
Python自动化运维之Ansible定义主机与组规则操作详解
Jun 13 Python
树莓派采用socket方式文件传输(python)
Jun 22 Python
python 并发编程 多路复用IO模型详解
Aug 20 Python
python 定义类时,实现内部方法的互相调用
Dec 25 Python
OpenCV4.1.0+VS2017环境配置的方法步骤
Jul 09 Python
python爬虫使用正则爬取网站的实现
Aug 03 #Python
python获取整个网页源码的方法
Aug 03 #Python
flask开启多线程的具体方法
Aug 02 #Python
基于opencv实现简单画板功能
Aug 02 #Python
django下创建多个app并设置urls方法
Aug 02 #Python
Django如何在不停机的情况下创建索引
Aug 02 #Python
如何用Anaconda搭建虚拟环境并创建Django项目
Aug 02 #Python
You might like
关于PHP内存溢出问题的解决方法
2013/06/25 PHP
PHP处理postfix邮件内容的方法
2015/06/16 PHP
Netbeans 8.2与PHP相关的新特性介绍
2016/10/08 PHP
php批量删除操作代码分享
2017/02/26 PHP
PHP实现时间比较和时间差计算的方法示例
2017/07/24 PHP
js截取固定长度的中英文字符的简单实例
2013/11/22 Javascript
windows8.1+iis8.5下安装node.js开发环境
2014/12/12 Javascript
浅谈JavaScript前端开发的MVC结构与MVVM结构
2016/06/03 Javascript
AngularJS模板加载用法详解
2016/11/04 Javascript
jQuery+ajax实现批量删除功能完整示例
2019/06/06 jQuery
vue自定义指令实现仅支持输入数字和浮点型的示例
2019/10/30 Javascript
vue中实现点击按钮滚动到页面对应位置的方法(使用c3平滑属性实现)
2019/12/29 Javascript
只有 20 行的 JavaScript 模板引擎实例详解
2020/05/11 Javascript
解决Vue-cli无法编译es6的问题
2020/10/30 Javascript
[10:07]2014DOTA2国际邀请赛 实拍选手现场观战DK对阵Titan
2014/07/12 DOTA
python实现ftp客户端示例分享
2014/02/17 Python
跟老齐学Python之赋值,简单也不简单
2014/09/24 Python
在Python中使用Neo4j数据库的教程
2015/04/16 Python
从Python程序中访问Java类的简单示例
2015/04/20 Python
Python 专题四 文件基础知识
2017/03/20 Python
python的一些加密方法及python 加密模块
2019/07/11 Python
Pandas DataFrame中的tuple元素遍历的实现
2019/10/23 Python
python GUI库图形界面开发之PyQt5下拉列表框控件QComboBox详细使用方法与实例
2020/02/27 Python
Python 调用有道翻译接口实现翻译
2020/03/02 Python
详解python的xlwings库读写excel操作总结
2021/02/26 Python
HTML5 canvas基本绘图之绘制曲线
2016/06/27 HTML / CSS
全球知名的珠宝首饰品牌:Kay Jewelers
2018/02/11 全球购物
医学院护理专业应届生求职信
2013/11/12 职场文书
毕业生找工作推荐信
2013/11/21 职场文书
员工拓展培训方案
2014/02/15 职场文书
学生生病请假条范文
2014/02/16 职场文书
个人年底工作总结
2015/03/10 职场文书
实验室安全管理制度
2015/08/05 职场文书
《风不能把阳光打败》读后感3篇
2020/01/06 职场文书
python pygame入门教程
2021/06/01 Python
python基础之类方法和静态方法
2021/10/24 Python