`
xiaoer_1982
  • 浏览: 1817144 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

expect的基本用法

阅读更多


www.diy567.com累了,去上面休息一下下,QQ空间,美文,非主流,网络日记,搞笑短信,祝福短信,热门短信,有意思啊

一、概述



Expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。

Expect是不断发展的,随着时间的流逝,其功能越来越强大,已经成为系统管理员的的一个强大助手。Expect需要Tcl编程语言的支持,要在系统上运行Expect必须首先安装Tcl。





二、Expect工作原理



从最简单的层次来说,Expect的工作方式象一个通用化的Chat脚本工具。Chat脚本最早用于UUCP网络内,以用来实现计算机之间需要建立连接时进行特定的登录会话的自动化。



Expect最简单的脚本操作模式本质上和Chat脚本工作模式是一样的。



例子:

1、实现功能

下面我们分析一个响应chsh命令的脚本。我们首先回顾一下这个交互命令的格式。假设我们要为用户chavez改变登录脚本,要求实现的命令交互过程如下:


QUOTE:

# chsh chavez

Changing the login shell for chavez

Enter the new value, or press return for the default

Login Shell [/bin/bash]: /bin/tcsh

#




可以看到该命令首先输出若干行提示信息并且提示输入用户新的登录shell。我们必须在提示信息后面输入用户的登录shell或者直接回车不修改登录shell。





2、下面是一个能用来实现自动执行该命令的Expect脚本:


CODE:

#!/usr/bin/expect

# Change a login shell to tcsh



set user [lindex $argv 0]

spawn chsh $user

expect "]:"

send "/bin/tcsh "

expect eof

exit




这个简单的脚本可以解释很多Expect程序的特性。和其他脚本一样首行指定用来执行该脚本的命令程序,这里是/usr/bin/expect。程序第一行用来获得脚本的执行参数(其保存在数组$argv中,从0号开始是参数),并将其保存到变量user中。



第二个参数使用Expect的spawn命令来启动脚本和命令的会话,这里启动的是chsh命令,实际上命令是以衍生子进程的方式来运行的。



随后的expect和send命令用来实现交互过程。脚本首先等待输出中出现]:字符串,一旦在输出中出现chsh输出到的特征字符串(一般特征字符串往
往是等待输入的最后的提示符的特征信息)。对于其他不匹配的信息则会完全忽略。当脚本得到特征字符串时,expect将发送/bin/tcsh和一个回车
符给chsh命令。最后脚本等待命令退出(chsh结束),一旦接收到标识子进程已经结束的eof字符,expect脚本也就退出结束。



3、决定如何响应



管理员往往有这样的需求,希望根据当前的具体情况来以不同的方式对一个命令进行响应。我们可以通过后面的例子看到expect可以实现非常复杂的条件响应,而仅仅通过简单的修改预处理脚本就可以实现。下面的例子是一个更复杂的expect-send例子:


CODE:

expect -re "\[(.*)]:"

if {$expect_out(1,string)!="/bin/tcsh"} {

send "/bin/tcsh" }

send " "

expect eof





这个例子中,第一个expect命令现在使用了-re参数,这个参数表示指定的的字符串是一个正则表达式,而不是一个普通的字符串。对于上面这个例子里是
查找一个左方括号字符(其必须进行三次逃逸(escape),因此有三个符号,因为它对于expect和正则表达时来说都是特殊字符)后面跟有零个或多个
字符,最后是一个右方括号字符。这里.*表示表示一个或多个任意字符,将其存放在()中是因为将匹配结果存放在一个变量中以实现随后的对匹配结果的访问。



当发现一个匹配则检查包含在[]中的字符串,查看是否为/bin/tcsh。如果不是则发送/bin/tcsh给chsh命令作为输入,如果是则仅仅发送一个回车符。这个简单的针对具体情况发出不同相响应的小例子说明了expect的强大功能。



在一个正则表达时中,可以在()中包含若干个部分并通过expect_out数组访问它们。各个部分在表达式中从左到右进行编码,从1开始(0包含有整个匹配输出)。()可能会出现嵌套情况,这这种情况下编码从最内层到最外层来进行的。



4、使用超时



下一个expect例子中将阐述具有超时功能的提示符函数。这个脚本提示用户输入,如果在给定的时间内没有输入,则会超时并返回一个默认的响应。这个脚本接收三个参数:提示符字串,默认响应和超时时间(秒)。


CODE:

#!/usr/bin/expect

# Prompt function with timeout and default.

set prompt [lindex $argv 0]

set def [lindex $argv 1]

set response $def

set tout [lindex $argv 2]




脚本的第一部分首先是得到运行参数并将其保存到内部变量中。


CODE:

send_tty "$prompt: "

set timeout $tout

expect " " {

set raw $expect_out(buffer)

# remove final carriage return

set response [string trimright "$raw" " "]

}

if {"$response" == "} {set response $def}

send "$response "

# Prompt function with timeout and default.

set prompt [lindex $argv 0]

set def [lindex $argv 1]

set response $def

set tout [lindex $argv 2]




这是脚本其余的内容。可以看到send_tty命令用来实现在终端上显示提示符字串和一个冒号及空格。set timeout命令设置后面所有的expect命令的等待响应的超时时间为$tout(-l参数用来关闭任何超时设置)。



然后expect命令就等待输出中出现回车字符。如果在超时之前得到回车符,那么set命令就会将用户输入的内容赋值给变脸raw。随后的命令将用户输入内容最后的回车符号去除以后赋值给变量response。



然后,如果response中内容为空则将response值置为默认值(如果用户在超时以后没有输入或者用户仅仅输入了回车符)。最后send命令将response变量的值加上回车符发送给标准输出。



一个有趣的事情是该脚本没有使用spawn命令。 该expect脚本会与任何调用该脚本的进程交互。



如果该脚本名为prompt,那么它可以用在任何C风格的shell中。





% set a='prompt "Enter an answer" silence 10'

Enter an answer: test



% echo Answer was "$a"

Answer was test

prompt设定的超时为10秒。如果超时或者用户仅仅输入了回车符号,echo命令将输出



Answer was "silence"



5、一个更复杂的例子



下面我们将讨论一个更加复杂的expect脚本例子,这个脚本使用了一些更复杂的控制结构和很多复杂的交互过程。这个例子用来实现发送write命令给任意的用户,发送的消息来自于一个文件或者来自于键盘输入。


CODE:

#!/usr/bin/expect

# Write to multiple users from a prepared file

# or a message input interactively



if {$argc<2} {

send_user "usage: $argv0 file user1 user2 ... "

exit

}




send_user命令用来显示使用帮助信息到父进程(一般为用户的shell)的标准输出。


CODE:

set nofile 0

# get filename via the Tcl lindex function

set file [lindex $argv 0]

if {$file=="i"} {

set nofile 1

} else {

# make sure message file exists

if {[file isfile $file]!=1} {

send_user "$argv0: file $file not found. "

exit }}




这部分实现处理脚本启动参数,其必须是一个储存要发送的消息的文件名或表示使用交互输入得到发送消的内容的"i"命令。



变量file被设置为脚本的第一个参数的值,是通过一个Tcl函数lindex来实现的,该函数从列表/数组得到一个特定的元素。[]用来实现将函数lindex的返回值作为set命令的参数。



如果脚本的第一个参数是小写的"i",那么变量nofile被设置为1,否则通过调用Tcl的函数isfile来验证参数指定的文件存在,如果不存在就报错退出。



可以看到这里使用了if命令来实现逻辑判断功能。该命令后面直接跟判断条件,并且执行在判断条件后的{}内的命令。if条件为false时则运行else后的程序块。


CODE:

set procs {}

# start write processes

for {set i 1} {$i<$argc}

{incr i} {

spawn -noecho write

[lindex $argv $i]

lappend procs $spawn_id

}





后一部分使用spawn命令来启动write进程实现向用户发送消息。这里使用了for命令来实现循环控制功能,循环变量首先设置为1,然后因此递增。循
环体是最后的{}的内容。这里我们是用脚本的第二个和随后的参数来spawn一个write命令,并将每个参数作为发送消息的用户名。lappend命令
使用保存每个spawn的进程的进程ID号的内部变量$spawn_id在变量procs中构造了一个进程ID号列表。


CODE:

if {$nofile==0} {

setmesg [open "$file" "r"]

} else {

send_user "enter message,

ending with ^D: " }




最后脚本根据变量nofile的值实现打开消息文件或者提示用户输入要发送的消息。


CODE:

set timeout -1

while 1 {

if {$nofile==0} {

if {[gets $mesg chars] == -1} break

set line "$chars "

} else {

expect_user {

-re " " {}

eof break }

set line $expect_out(buffer) }



foreach spawn_id $procs {

send $line }

sleep 1}

exit


上面这段代码说明了实际的消息文本是如何通过无限循环while被发送的。while循环中的 if判断消息是如何得到的。在非交互模式下,下一行内容从消息文件中读出,当文件内容结束时while循环也就结束了。(break命令实现终止循环) 。

在交互模式下,expect_user命令从用户接收消息,当用户输入ctrl+D时结束输入,循环同时结束。 两种情况下变量$line都被用来保存下一行消息内容。当是消息文件时,回车会被附加到消息的尾部。

foreach循环遍历spawn的所有进程,这些进程的ID号都保存在列表变量$procs中,实现分别和各个进程通信。send命令组成了
foreach的循环体,发送一行消息到当前的write进程。while循环的最后是一个sleep命令,主要是用于处理非交互模式情况下,以确保消息
不会太快的发送给各个write进程。当while循环退出时,expect脚本结束。


三、参考资源


Expect软件版本深带有很多例子脚本,不但可以用于学习和理解expect脚本,而且是非常使用的工具。一般可以在/usr/doc
/packages/expect/example看到它们,在某些linux发布中有些expect脚本保存在/usr/bin目录下。



一些有用的expect脚本

autoexpect:这个脚本将根据自身在运行时用户的操作而生成一个expect脚本。它的功能某种程度上类似于在Emacs编辑器的键盘宏工具。一个自动创建的脚本可能是创建自己定制脚本的好的开始。

kibitz:这是一个非常有用的工具。通过它两个或更多的用户可以连接到同一个shell进程。

tkpasswd: 这个脚本提供了修改用户密码的GUI工具,包括可以检查密码是否是基于字典模式。这个工具同时是一个学习expect和tk的好实例。

分享到:
评论

相关推荐

    Linux经典脚本expect的示例及基本用法

    而Expect就使用来实现这种功能的工具。 Expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。Expect的作者有如下定义:Expect是一个用来实现自动交互功能的软件套件(Expect [is a] ...

    gaoljhy#blog#expect用法1

    基本上认识英文的都知道这是设置超时时间的,现在只要记住他的计时单位是:秒spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expec

    失物招领系统java源码-Expect-for-Java:Expect工具的纯Java实现

    工具有一些基本的了解。 依赖关系 期待.java: TestExpect.java: 如何使用 JavaDoc 解释了如何使用该类。 您可能会发现以下内容很有用: 注意 Expect 不提供“永远”超时,您可以为此目的使用非常大的整数,例如。 ...

    Python Pexpect库的简单使用方法

    简介 最近需要远程操作一个服务器并执行该服务器上的一个python脚本,查到可以使用Pexpect这个库。记录一下。...Pexpect的主要特点是需要Python的基本库pty,这个库只有在类Unix系统上才有 Pexpect关于

    serial-spec:规范 api 请求的更好方法

    基本用法 require "spec_helper"RSpec . describe "test" do include SerialSpec request_method "GET" request_path "/" it_expects ( :content_encoding ) { expect ( status ) . to eq ( 200 ) } it_expects ( :...

    ean13-lib:提供常见的EAN 13条码相关功能

    EAN 13库基本功能的打字稿库。安装$ npm i ean13-lib --save用法号码验证返回输入(13个长度的数字字符串)是否为EAN 13数字。 import { Ean13Utils } from 'ean13-lib';const result = Ean13Utils.validate('...

    rspec-collection_matchers:从rspec-expectations中提取的集合基数匹配器

    items安装将此行添加到您的应用程序的Gemfile中: gem 'rspec-collection_matchers'然后执行: $ bundle或将其自己安装为: $ gem install rspec-collection_matchers基本用法首先,您需要rspec-collection匹配器。...

    unittestscaffold:使用 gulp 和 browserify 进行单元测试的基本设置

    ##使用 Gulp 和 Browserify 时的单元测试###Description 在项目中使用和时,使用 (用于测试运行)和进行单元测试(用于测试)的基本设置(describe、expect...)。 ###用法$ git clone ...

    mpwn:单个文件ctfexploit客户端库-python3,带注释的类型

    基本用法: from mp import * # p = remote('host', port) p = process ( './exe_name' ) # basic io: p . sendline ( 'hello world' ) print ( p . recvline ()) p . send ( 'hi' ) print ( p . recv ( 5 )) # ...

    sonar:HTTP请求模拟工具

    基本用法npm install sonarSonar的工作方式是包装处理程序或应用程序实例,并公开一个简单的HTTP API以生成同步请求/响应对象。 默认情况下,Sonar将捕获所有结果响应数据并将其放置在响应的body属性中。 HTML响应...

    shellac:将您的shell脚本涂上一些更漂亮的东西

    用法import shellac from 'shellac'test ( 'morty' , async ( ) =&gt; await shellac ` $ echo "End-to-end CLI testing made nice" $ node -p "5 * 9" stdout &gt;&gt; ${ ( answer ) =&gt; expect ( Number ( answer ) ) ....

    javascript-testing:具有karma,mocha,chai,sinon和phantomjs的Javascript项目的基本测试示例

    JavaScript测试这个例子的目的是要知道如何为Javascript项目编写测试。 配置工具。 在非UI浏览器中运行测试: 。 模拟依赖关系。 使用Sinon替换服务器请求。... 还选择了Expect,因为它不会修改对象原型

    Shell脚本专家指南

    《Shell脚本专家指南》旨在为Linux、Unix以及OSx系统管理员提供短小精悍且功能强大的shell实现解决方案,教会读者如何使用现有调试器调试shell脚本。全书分为3个部分:脚本技术基础、系统交互和高级技术、有用的脚本...

    跟老男孩学Linux运维:Shell编程实战

    前 言第1章 如何才能学好.../ 310第18章 Expect自动化交互式程序应用实践 / 317第19章 企业Shell面试题及企业运维实战案例 / 340第20章 子Shell及Shell嵌套模式知识应用 / 377附 录 Linux重要命令汇总 / 393

    Myxo:C#中的茉莉花

    基本测试使用 Jasmine BDD 风格的Describe/It/Expect结构表达。例子 using static Myxo . Methods ;namespace Calc . Test{public class Program{public static void Main (){Describe ( " Calcula

    serializable:用于制作可序列化对象的mixin

    包括mixin并实现两个实例方法( ::serializeParams和::deserializeParams )以向您的类添加序列化。 使用可序列化的类 基本 在深入探讨如何实现可序列化的类之前,让我们先谈谈如何使用它们。 要序列化对象,请调用...

    heroku上的chrome最小:在heroku上运行无头chrome

    这是使此工作正常的基本需求/注意事项: Chrome选项上有一些很难设置的配置标志,如果您在家中要注意,请注意new_browser方法。 使用watir可以简化脚本编写,但是可以随意使用原始Selenium。部署方式您可以使用以下...

    NitroRecorder-crx插件

    NitroRecorder是一个Javascript UI用户动作记录器和测试规范代码转换器##简而言之-&gt;它为您编写代码##使用方法:只需在您要测试其功能的Web UI上单击扩展程序的图标即可:通过侦听4种事件类型来跟踪用户活动:“单击...

    RED HAT LINUX 6大全

    本书内容翔实、涉及领域广泛,并且提供了详细的例子和大量的参考资料(包括书籍、电子文档和Internet站点),是一本学习、使用和管理Linux不可多得的好书。 目 录 译者序 前言 第一部分 Red Hat Linux的介绍与安装 ...

    property-grid:React属性网格

    基本用法: /** * The onChange function can expect the following params: * @param { Event } event The React event that triggered the change * @param { Object } prop The property on which the ...

Global site tag (gtag.js) - Google Analytics