很多linux程序比如passwd,ftp,scp,ssh等自身并没有提供一种静默式的执行选项,而是依赖于运行时的终端输入来进行后一步的操作比如更改密码、文件上传、下载等。虽然有些编程语言如java嵌入了不少这些常用工具的API比如jcsh等,但是毕竟他们不够自然和顺手。虽然也可以使用ssh免登陆方式,但当机器太多且密码可能经常会更改的时候,每次大批量修改也会很不方便。

expect是unix/linux下的一个命令行工具,其使用tcl作为编程语言开发。其主要的功能就是模拟终端用户控制交互式应用程序。简单而言,expect就是针对其所调用的程序的输出使用正则表达式进行判断,然后根据不同的匹配模式执行不同的action,其他的都是辅助性的。所以,其实就功能而言,类似expect的功能可以使用java/python/perl甚至c语言进行直接开发,当然没必须要重新发明轮子。

因为expect使用tcl开发的,所以了解必要的基础tcl语法对于编写expect控制脚本是绝对必要的。可参考官网http://www.tcl.tk/,不过tcl现在似乎用的相当少了,在TIOBE排名中好像都没进过前50。

从实际开发角度来说,expect是如下结构:

启动交互式命令

if 匹配模式1 { 执行动作1 }

if 匹配模式2 { 执行动作2 }

if 匹配模式3 { 执行动作3 }

expect主要有如下关键的命令(这一点上就比较类似于SQL):

  • spawn,用于启动一个进程,这个进程通常是必须交互式才能执行的,否则shell就可以了,没必要整合到expect中执行。如spwan ftp ftp.uu.net
  • expect,设置希望匹配的模式,比如expect "hi\n",也支持锚定如expect "^hi\n",正则表达式如expect "hi*\n"等,默认情况下expect会等待10秒,超过超时时间后会自动到下一个命令执行,可通过set timeout修改超时时间。对于匹配模式前的内容,其存储在一个内置变量expect_out(buffer)中
  • send,接收一个字符串作为参数,并发送给进程。

安装

一般现在的linux发行版都带了expect rpm,但大部分生产最小化安装时都不会默认安装。可以使用yum安装,yum install expect,会安装tcl以及expect。

安装完成后,可执行expect,如果进入了expect控制台就代表已经成功安装了。

脚本模式运行

跟其他脚本语言一样,如果要在脚本中运行expect一样,需要告诉操作系统执行这个脚本的时候,调用/usr/bin下的expect解释器,如下:

#!/usr/local/bin/expect --

匹配模式的写法

以下格式之一的expect语法都是可以的:

expect "hi" {send "You said $expect_out(buffer)"}

expect "hi" { send "You said hi\n" } \
    "hello" { send "Hello yourself\n" } \
    "bye" { send "That was unexpected\n" }

expect {
  "hi" { send "You said hi\n"}
  "hello" { send "Hello yourself\n"}
  "bye" { send "That was unexpected\n"}
}

expect {
  "hi" {
    send "You said hi\n"
  }
  "hello" {
  send "Hello yourself\n"
  }
  "bye" {
  send "That was unexpected\n"
  }
}

后面两种应该来说可读性好很多。

在action里面可以使用任何的tcl逻辑语句如if,while等,如下:

while 1 {
  expect {
    "2" break
    "1"
  }
  someproc
}

expect {
  a {set foo bar}
  b {
    if {$a == 1} {set c 4}
    set b 2
  }
}

expect匹配正则表达式

expect对于正则表达式的还是比较强大的,基本上常规的都可以支持。但有几个注意点:

1、在tcl中,[]是特殊符号,意味着如果需要使用区间的模式,需要转义,如下:

expect "\[a-f0-9]"或expect {[a-f0-9]}都可以,{}中的内容会被当做常量对待,所以推荐前者。

expect分支、超时和异常处理

在编写自动化脚本时,我们通常需要根据不同的输出采取不同的分支,比如对于连接拒绝,密码错误等需要退出脚本,只有正确的情况下才继续执行脚本剩余部分。

通常的分支如下:

expect {
  "hi" {send "You said hi\n"}
  "hello" {send "Hello yourself\n"}
  "bye" {exit}

"other" 
}

在遇到hi,hello,bye时执行不同分支,在遇到other时什么都不做。不过只有最后一个分支才能没有action部分。上述exit表示退出expect脚本。可以带返回值,如exit 0表示正确返回,exit -1代表错误。

action部分可以由多个命令组成,如{puts "exit"; exit},对于多个命令组成的语句,必须用{}括起来或者换行(换行也是tcl一个命令终止的结束符,不过一般建议使用;就如js一样)。

有些命令会执行超时,这个时候在expect分支中可以使用 timeout { puts "timeout"; },timeout是expect保留关键字,不能用引号括起来,否则就当做字符串处理了。

expect脚本参数

通常,我们会调用在脚本中的expect命令,其他上下文信息通过参数的方式传递给expect。

在expect中,参数通过lindex $argv N的方式进行引用,如下:

set timeout [lindex $argv 0]
spawn [lindex $argv 1]

如果需要启动带命令行选项的进程怎么办呢?通常我们会通过下列方式执行:

spawn [lrange $argv 1 end]

但会发现报命令无法找到或者类似错误。这是因为spawn会将lrange的结果当做程序名而不是程序名+命令行参数进行解析,所以要使用如下的expect命令执行:

eval spawn [lrange $argv 1 end]

eval告诉解析器后面以标准命令的方式执行,而不是作为解析后的字符串。

eof

大部分网络程序在结束前都会关闭连接,因此会在最后包含eof,例如,对于ping命令:

spawn ping $host
set timeout 2
expect "alive" {exit 0} timeout {exit 1}

假设在超时前终止了,此时expect程序就可能会异常。所以对这些操作,应考虑在最后加上eof {exit 1}。

默认行为

因为任何时候,程序可能的返回值很有可能无法穷举,这个时候,要么使用*进行完全匹配,不过更合理的处理方式时有类似其他语言中的switch default分支。

在expect中,我们可以这么写expect "alive" {exit 0} default {exit 1}。

expect入门--自动化linux交互式命令的更多相关文章

  1. 两种Linux下非交互式命令的实现

    一.概述 在Linux环境,有多种实现自己主动化的脚本语言.如Shell.Python.Perl.Tcl等. Shell语言因与Shell外壳结合紧密,是最常见的实现自己主动化的脚本语言. 同一时候, ...

  2. 使用expect实现自动交互,shell命令行自动输入,脚本自动化,变量引用,expect spawn执行带引号命令,expect 变量为空,不生效,不能匹配通配符*,函数,数组

    背景 有需求,在允许命令或者脚本跳出交互行,需要进行内容输入,但需要人手动输入,不是很方便,此时可以通过expect来实现自动互动交互. expect是一个自动交互功能的工具,可以满足代替我们实际工作 ...

  3. Linux Shell脚本入门--cut命令

    Linux Shell脚本入门--cut命令 cut cut 命令可以从一个文本文件或者文本流中提取文本列. cut语法 [root@www ~]# cut -d'分隔字符' -f fields &l ...

  4. 交互式命令 expect

    shell尽管很强大.但是貌似无法完成交互式命令的操作,实例 ssh host 如果host而且该机没有加入信任.手动输入的时间需要password. 这样的情况下可以使用expect支持. 下面举个 ...

  5. Linux Shell脚本入门--wget 命令用法详解

    Linux Shell脚本入门--wget 命令用法详解 wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上.它有以下功能 ...

  6. Linux Shall命令入门

    Linux Shall命令入门 ifconfig                                            //查看ip信息 service network start   ...

  7. [转帖]linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)

    linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习) https://www.cnblogs.com/caozy/p/9261224.html 总结的挺好的 ...

  8. Linux常用命令入门文件、网络、系统及其他操作命令

    Linux常用命令入门文件.网络.系统及其他操作命令.压缩 归档 文件系统 系统管理 用户管理  网络管理 finger 相关命令 netstat ping rsh telnet wget 进程管理等 ...

  9. Linux 入门记录:十六、Linux 多命令协作:管道及重定向

    一.多命令协作 在 Linux 系统当中,大多数命令都很简单,很少出现复杂功能的命令,每个命令往往只实现一个或多个很简单的功能.通过将不同功能的命令组合一起使用,可以实现某个复杂功能的. Linux ...

随机推荐

  1. POJ 1012 Joseph

    Joseph Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44650   Accepted: 16837 Descript ...

  2. 解决“iOS 7 app自动更新,无法在app中向用户展示更新内容”问题

    转自cocoachina iOS 7能在后台自动app,这对开发者来说和用户都很方便,但是还是有一些缺点.用户不会知道app本次更新的内容,除非他们上到app的App Store页面去查看.开发者也会 ...

  3. 《Programming with Objective-C》第三章 Working with Objects

    Object和普通变量的区别 If you’re used to using terms like the stack and the heap, a local variable is alloca ...

  4. [Git] 快速签出与更新所有远程分支.md

    git-fetch 命令从远程仓库复制 heads 和 tags 信息到本地,保存在临时文件 .git/FETCH_HEAD 中以备 git-merge 命令使用. 你可以使用 git fetch 命 ...

  5. solr的建议搭建

    公司培训了solr,我打算自己练练手!就下载了solr-4.4.0.zip~呵呵 1.基本环境Tomcat 1.6 和JDK1.6 2.解压solr-4.4.0.zip , 把dist/solr-4. ...

  6. [Math] Beating the binary search algorithm – interpolation search, galloping search

    From: http://blog.jobbole.com/73517/ 二分检索是查找有序数组最简单然而最有效的算法之一.现在的问题是,更复杂的算法能不能做的更好?我们先看一下其他方法. 有些情况下 ...

  7. Ladda – 把加载提示效果集成到按钮中,提升用户体验

    Ladda 是一组集成了加载提示的按钮,以弥合行动和反馈之间的时间间隔,提供更好的功能使用体验.主要用于在用户点击提交之后,向用户提供即时的反馈,让他们知道浏览器正在处用户提交的任务. 您可能感兴趣的 ...

  8. Xcode-Xcode 7.3 解决不能自动联想问题

    一.问题: 升级Xcode 7.3 之后发现导入头文件之后,没法自动联想. 二. 解决办法: 打开Xcode --> Target --> BuildSettings --> App ...

  9. js-基础(1)

    js-基础(1) javascript由三部分组成:核心,DOM,BOM核心——ECMAScript,可以运行浏览器/单纯的JS引擎    console.log(‘hello’);DOM——操作HT ...

  10. 拓扑图弹力布局呈现Flickr图片搜索结果

    十年前有值得分享的图片我都存在Flickr上,可惜yahoo收购了Flickr之后堕落​好多年,最近yahoo在梅姐带领下Flickr团队终于恢复了生机,个人免费存储空间扩充到了1T,界面用户体验也有 ...