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 相关文章推荐
以一段代码为实例快速入门Python2.7
Mar 31 Python
Python实现的redis分布式锁功能示例
May 29 Python
python 列表,数组和矩阵sum的用法及区别介绍
Jun 28 Python
django连接mysql配置方法总结(推荐)
Aug 18 Python
python+splinter实现12306网站刷票并自动购票流程
Sep 25 Python
对python多线程SSH登录并发脚本详解
Feb 14 Python
Pyqt5如何让QMessageBox按钮显示中文示例代码
Apr 11 Python
python使用原始套接字发送二层包(链路层帧)的方法
Jul 22 Python
python 模拟贷款卡号生成规则过程解析
Aug 30 Python
python进程间通信Queue工作过程详解
Nov 01 Python
Python图像处理库PIL的ImageEnhance模块使用介绍
Feb 26 Python
Python 如何将integer转化为罗马数(3999以内)
Jun 05 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简单实现欧拉函数Euler功能示例
2017/11/06 PHP
php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
2020/02/21 PHP
Javascript实现页面跳转的几种方式分享
2013/10/26 Javascript
用json方式实现在 js 中建立一个map
2014/05/02 Javascript
jquery实现在页面加载完毕后获取图片高度或宽度
2014/06/16 Javascript
javascript引用赋值(地址传值)用法实例
2015/01/13 Javascript
jQuery中$(function() {});问题详解
2015/08/10 Javascript
js实现带圆角的多级下拉菜单效果
2015/08/28 Javascript
jquery判断复选框是否被选中的方法
2015/10/16 Javascript
JS弹出层遮罩,隐藏背景页面滚动条细节优化分析
2016/04/29 Javascript
javascript实现将数字转成千分位的方法小结【5种方式】
2016/12/11 Javascript
js canvas实现擦除效果示例代码
2017/04/26 Javascript
微信小程序 空白页重定向解决办法
2017/06/27 Javascript
ES6模块化的import和export用法方法总结
2017/08/08 Javascript
JS组件系列之Gojs组件 前端图形化插件之利器
2017/11/29 Javascript
JS函数节流和函数防抖问题分析
2017/12/18 Javascript
使用vue.js在页面内组件监听scroll事件的方法
2018/09/11 Javascript
深入理解JavaScript的值传递和引用传递
2018/10/24 Javascript
Vue CLI 2.x搭建vue(目录最全分析)
2019/02/27 Javascript
js核心基础之构造函数constructor用法实例分析
2019/05/11 Javascript
解决 viewer.js 动态更新图片导致无法预览的问题
2019/05/14 Javascript
npm ci命令的基本使用方法
2020/09/20 Javascript
django之常用命令详解
2016/06/30 Python
Pyinstaller打包.py生成.exe的方法和报错总结
2019/04/02 Python
python经典趣味24点游戏程序设计
2019/07/26 Python
python属于跨平台语言码
2020/06/09 Python
优秀员工表扬信
2014/01/17 职场文书
迅雷Cued工作心得体会
2014/01/27 职场文书
协议书模板
2014/04/23 职场文书
学校党的群众路线教育实践活动对照检查材料
2014/09/24 职场文书
授权委托书(法人单位用)
2014/09/29 职场文书
商业门面租房协议书
2014/11/25 职场文书
离婚协议书范文2014(夫妻感情破裂)
2014/12/14 职场文书
关于教师节的广播稿
2015/08/19 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers
python读取mat文件生成h5文件的实现
2022/07/15 Python