• expect入门--自动化linux交互式命令


    很多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 ",也支持锚定如expect "^hi ",正则表达式如expect "hi* "等,默认情况下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 " }
        "hello" { send "Hello yourself " }
        "bye" { send "That was unexpected " }

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

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

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

    在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 "}
      "hello" {send "Hello yourself "}
      "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}。

    注:如果会使用java开发的话,也推荐使用jsch库http://www.jcraft.com/jsch/。

  • 相关阅读:
    手把手教你用Python模拟登录淘宝
    数据库链接方式ORM
    ubuntu命令
    django项目不能运行解决方法
    区别比较 match和search
    redis持久化RDB与AOF
    python基础数据类型
    python基础二
    Python中将一个对象倒序输出的4种方法
    python基础数据类型补充以及编码的进阶
  • 原文地址:https://www.cnblogs.com/zhjh256/p/5930874.html
Copyright © 2020-2023  润新知