expect tcl 摘录

部分参考来源说明

Expect 手册中文版
Expect学习笔记
tcl英文手册

例子

#!/usr/bin/expect
# ssh
# send_user -- 用来避免后面出现以-开头的用户提示信息被解释成非法参数
#send_user -- "---------------------------------\n"    
if { $argc < 4 } {
    send_user " ERROR : Invalid arguments.\n"
    send_user " Usage : $argv0 host user pw cmd\n"
    exit 10
}

set host [ lindex $argv 0 ]
set user [ lindex $argv 1 ]
set pw   [ lindex $argv 2 ]
set cmd  [ lindex $argv 3 ]
set timemout 15

spawn ssh $user@$host $cmd
# 获取spawn_id
set ssh_id $spawn_id

#  Note : exp_internal要位于spawn后, 0表示关闭调试模式,非0表示开启调试模式 , -f file表示调试内容写入文件。
#         组合使用时: exp_internal -f file 0 ,后面的0表示调试信息仅仅写到文件,如果后面是1则调试信息写入文件同时输出到stdout
exp_internal -f /tmp/exp_exec.log 0

expect {
    -nocase "yes/no" {
        exp_send "yes\r"
        # Notice : exp_continue必须处于expect内,它能让expect再次从第一次匹配
        exp_continue
    }
    -nocase "password:" {
        exp_send "${pw}\r"
	expect  "try again" {
		send_user "\nERROR: Password is incrrect!\n"
		# close不带参数时默认关闭当前spawn_id
		close $ssh_id
		exit 12
	}
    }

    # Note: default 包含了timeout和eof
    default {
        send_error "ERROR : timeout or eof.\n"
        close $ssh_id
        exit 11
   }
}

expect命令

核心命令有三个 spawn、expect、send

  • spawn用于启动一个进程
    -ignore选项用于忽略信号,例如: spawn –ignore SIGINT –ignore SIGHUP ping $host #就会屏蔽发送给ping进程的中断和挂起信号
  • expect用于匹配
    用法1: 
        expect 表达式 {动作} 表达式 {动作} ...   
    用法2:
        expect {
            表达式 {动作}
            表达式 {动作}
            ...
        }
    
    两种用法是一样的,但是第二种用法格式比较清晰
    
    使用expect_before或expect_after偷懒:
        修改前:
        expect {
            "done" { puts "Done" }
            "p1" { puts "p1" }
        }
        expect {
            "done" { puts "Done" }
            "p2" { puts "p2" }
        }
        修改后:
        expect_before “done” { puts "Done" }
        expect {
            "p1" { puts "p1" }
        }
        expect {
           "p2" { puts "p2" } 
        }
    如果上面第二个expect块后面还有expect_before,则后面的expect_before会覆盖前面的expect_before。当然如果上面每个expect块中都有"done"表达式,那么块内的优先级会比expect_before的要高
  • send 用来发动作的,也可以使用exp_send命令(exp_send是send的别名)。 exp_send有两个选项:-i和-s,选项具体含义看后面说明。支持八进制和十六进制发送,比如exp_send "\r" 可以写成 exp_send "\015"或exp_send "\x0d"

其他expect命令

  • expect_user匹配用户输入,而前面的expect是匹配程序输出的。
    expect_user {
        -re {[cC]hina} { puts stdout "中国" }
        -re {[jJ]apan} { puts stderr "日本" }
    }
    上面的例子是如果用户输入china/China就打印"中国",输入japan/Japan就打印"日本"
  • exp_continue 是expect块中的动作,作用就是从块的开始部分重新匹配表达式
  • exp_internal 调试命令。
    exp_internal  0      关闭调试。
    exp_internal  1      开启调试,输出到标准输出中。
    exp_internal –f file 0  调试信息写入文件,但不写到标准输出。
    exp_internal –f file 1  调试信息写入文件,也写到标准输出。
  • exp_pid 这个命令用于获取spawned启动的进程的进程
    ID号,注意exp_id不是spawn_id。
    set pid0 [ exp_pid –i $spawn_id ]  #使用exp_pid获取spawned进程id,并赋值给pid0变量
    send_user "spawned进程的pid是[ exp_pid –i $spawn_id ]\n" #打印spawned进程的id
  • send_user 相对于send,exp_send发送数据给进程,send_user是发送数据给标准输出。send_error是类似的命令,只不过输出到标准错误
  • send_log 命令输出到日志文件中。需要配合log_file命令使用
  • log_file 命令用来将输出记录到一个文件中去,使用格式如下:
    log_file  <选项>  文件名 当这个命令带有文件名时,表示将spawn程序的标准输出记录到文件中(我测试的结果是send_user的文本也进来了),只使用log_file命令但不带文件名则表示关闭记录。
    
    log_file的选项:
    -leaveopen 当文件已经被打开时,不继续向这个文件中添加内容。
    -noappend  如果文件已存在,那么清空文件中的内容,然后再写入。
    -a         如果文件已存在,则将新内容附加到当前文件的末尾。
  • log_user 命令,log_user 0 表示关闭spawn的所有输出,log_user 1表示spawn输出到标准输出。不太确定,还是贴上man手册
    log_user -info|0|1
             By default, the send/expect dialogue is logged to stdout (and a logfile if open).  The logging to stdout is disabled by the command "log_user 0" and reenabled by "log_user 1".   Logging  to
             the logfile is unchanged.

             The -info flag causes log_user to return a description of the most recent non-info arguments given.
  • 总结一下上面的输出:主动使用send_user或send_error的输出,主动使用send_log写文件的输出。还有使用log_user控制spawn send/expect是否输出到标准输出

  • close close命令用来关闭连接,它支持-i选项,用来关闭指定句柄的过程,如果不带任何选项,则关闭当前$spawn_id变量指定的过程。

  • wait wait命令与close命令相似,都是用来关闭连接的,但wait命令是等待系统主动返回eof,也就是结束信号后才关闭,而不是像close那样无条件关闭,与close命令一样,它也支持-i选项。

  • remove_nulls expect中,默认会去掉返回中的控制符,注意:不要将控制符与空白符搞混,控制符主要是信号,他们是不会显示在屏幕上的,比如使用ctrl+c(中断)、ctrl+d(终止)等组合键发送的信号,信号是ASCII码表中01-31区间中的字符;空白符则是可以显示出来的空白符号,比如空格、回车、换行、制表等一系列符号。
    remove_nulls命令可以控制是否去掉返回中的控制符,使用方法如下:
    remove_nulls 0 #关闭自动去掉控制符的功能
    remove_nulls 1 #开始知道去掉控制符的功能,这是默认值。

  • match_max 用来设置expect_out(buffer)变量的缓存大小,默认情况下expect_out(buffer)变量缓存是2000个字符,你可以设置这个大小来设置更符合实际的缓存,使用方法如下:match_max 65535 支持-i或-d选项,-i和-d见本文的选项介绍

  • trap 信号处理,语法是 trap [[command] signal], 例如expect默认有:trap exit

    1-捕获到SIGINT HUP QUIT信号后,打印信号名和信号数值
    trap {
       send_user "signal name is [trap –name]\n"  # -name选项用来显示信号名
       send_user“signal integer is [trap –number]” # -number选项显示信号数值
       exit
    } {SIGINT SIGHUP SIGQUIT} 
    
    2-取消某些信号
     trap SIG_IGN { SIGINT SIGHUP SIGQUIT}
    
    3-恢复信号的默认处理
    trap SIG_DFL { SIGINT SIGHUP SIGQUIT }
  • exit 退出命令,语法 exit [-opts] [status]。
    exit –onexit {
       send_user“Good bye\n”
    }
    # -onexit选项后面可以跟onexit的handler,做扫尾工作。这些命令都可以man expect找到说明
  • interact 该命令是Expect中非常重要的命令之一,它用来在脚本中将控制权交给用户,由用户与spawn生成的进程进行交互。细节可以man expect
     例子:  # 输入完密码后,用户可以和远端shell交互,按q或ctrl+D将控制权重新还给脚本
    spawn ssh root@192.168.1.111
    interact {
        "q"     {return} 
        "\004"  {return}    # ascii 004是EOT 也就是ctrl+D
    }
    
    expect {
        ....
    }
  • interpreter 调用解释器,可以用于调试,比如puts变量内容。调试完后,可以使用return返回

expect命令的选项

  • -d选项 几乎所有expect命令都支持-d选项,d代表default,也就是设置某些命令的默认值,比如:
    remove_nulls –d 1
    timeout –d 30 #设置默认超时
  • -i选项 一般用于同时控制多个spawn进程。
  1.例如spawn好几个进程,每个spawn后面通过类似 set sp_id0 ${spwan_id}的命令 获取操作这个spawn进程的句柄。后面通过这个spawn id来控制,例如 exp_send -i ${sp_id0} "commmand1\r" 
  2.再例如,在expect的过程中使用spawn id才针对性匹配。比如:
    spawn ./hotpotcmd
    set hid ${spawn_id}
    spawn  ./barbecure
    set bid ${spawn_id}
    expect {
	    -i $hid
	    -re {hot[pP]ot} { send_user "hotpot ok\n" }
    }
    expect {
	    -i $bid
	    -re {[bB]arbecure} { send_user "barbecure ok\n" }
    }
  • -f选项,f代表 file ,某些Expect命令支持这个选项,比如exp_internal命令,这个选项用来将某些命令的输出放入一个文件中去,因此这个选项后面必须带有文件的路径作为值。
  • -s选项
    s代表slowly,也就是发送速度,这个选项一般用于send族命令中,比如send、exp_send、send_user、send_error等等,使用这个选项之前,必须先对send_slow变量赋值,send_slow变量设置expect发送字符的速度,它接受2个参数,一个是字符个数,另一个是时间,使用方法如下:
    set send_slow {character seconds}
    第一个参数是字符个数,第二个是时间,单位为秒,比如:set send_slow {10 1} 表示每秒钟发送10个字符,当然如果生效,send命令必须加上-s参数,比如:set send_slow {10 1}; send -s “hello\r”
  • -h选项 代表human,用来模拟人敲击键盘的动作,可以用于所有send命令族,比如exp_send、send_user等等,使用之前必须先对send_human变量赋值。例如:set send_human {.1 .5 1 .05 2} 四个参数分别表示:.1每个字母输入的平均间隔(0.1秒).5表示单词输入完后停顿时间。1表示间隔时间变化的剧烈程度,取值0到无穷大,1表示比较合理的,需要结合最后两个参数。.05表示输入字符最小间隔时间,2表示输入字符最大间隔时间。
  • -gl选项,代表global,用于指定全局类型的表达式,用于expect、interact命令族中,比如expect、expect_user、expect_error等,global形式的表达式与DOS的通配符相似,用*表示任意多个任意字符,?表示一个任意字符,这是一种很简单的表达式
  • -ex选项,代表exact,用于指定精确类型的表达式,用于expect、interact命令族中,这种类型的表达式特点就是所有字符都精确代表它本身的含义,不存在通配符。
  • -re选项代表regular expression,也就是正则表达式,用于expect、interact命令族中
  • -null选项,这个选项可以用于expect和send过程,用于expect时表示连同空字符也一样做匹配(默认情况下不匹配),用于send则用于发送空字符,在send命令中还可以一次发送多个空字符,比如:send –null 3
  • -ignore选项,这个选项用于spawn命令,用来忽略某些特殊的信号,比如忽略ctrl+c和ctrl+d:spawn–ignore SIGINT –ignore SIGHUP ping $host
  • -info选项用于expect_before和expect_after命令中,用于对这两个命令的调试
  • -onexit见上面的exit命令,-number和-name选项见trap命令,这里省略
  • --选项,表示选项的终止

变量

  • expect_out(buffer),数组,这个变量中放置从上一次匹配到这一次匹配之间的所有返回,包括匹配字符本身。
  • spawn_id 专门用于expect中的进程管理

tcl摘录

数据类型

  • tcl只有一种数据类型--字符串

符号

  • $ 变量展开(substitution). $var或${var}是标量变量展开,$var(index)是数组变量展开
  • [] 方括号,命令展开,也就是执行括号内的命令,例如set kernel [ exec bash -c {uname -r} ] # kernel的值为内核版本号
  • " 双引号把词组标记为命令的一个参数. 注意:"$"符号和方括号在双引号内仍被expect解释
  • { } 大括号也把词组标记为命令的一个参数. 但是, 其他符号在大括号内不被解释(保持原样)
  • \ 反斜线\表示转义,支持八进制、16进制、unicode: \ooo \xhh \uhhhh

命令

  • 参考 http://www.tcl-lang.org/man/tcl8.6/TclCmd/contents.htm,下面只摘录部分
  • set 用于变量赋值,unset用于清除变量。 例如set var "xxxx" #普通变量; set week(mon) 1 #赋值数组; set d [expr 10+15]
  • expr
  • format 类似于c的sprintf。例如 set var [ format "year=%s mon=%s" $year $mon]
  • scan 类似c的sscanf。例如 scan "some 26 34" "some %d %d" a b
  • regexp 正则匹配。语法 regexp [switchs] [--] expr_string [matchVar] [submatchVar] [submatchVar]...
    switch支持 -nocase -line
    regexp {(cn|jp|kr) +([0-9]+) km} "cn 4022 km" all country num 
    puts "all=$all country=$country num=$num"
    回显:all=cn 4022 km country=cn num=4022
  • append 追加到变量,例如 set var "af"; append var ":01" ":b3" #则var值为"af:01:b3"
  • lappend — Append list elements onto a variable
  • lassign 列表赋值
    lassign {a b c} x y z       ;# Empty return
    puts $x                     ;# Prints "a"
    puts $y                     ;# Prints "b"
    puts $z                     ;# Prints "c"
  • linsert 列表插入,参考手册
  • lindex 列表取值(可以多个),参考手册
  • 其他列表操作: list, lappend, linsert, llength, lsearch, lset, lsort, lrange, lreplace, string 自己参考
  • dict 字典,
  • join 合并
  • expr 数学计算
  • if
    if {$vbl == 1} {
       puts "vbl is one"
    } elseif {$vbl == 2} {
        puts "vbl is two"
    } else {
        puts "vbl is not one or two"
    }
  • for和foreach
    for {set x 0} {$x<10} {incr x} {
        puts "x is $x"
    }
    
    set x {}
    foreach {i j} {a b c d e f} {
        lappend x $j $i
    }
    # The value of x is "b a d c f e"
    # There are 3 iterations of the loop.
    The next loop uses i and j to iterate over two lists in parallel.

    set x {}
    foreach i {a b c} j {d e f g} {
        lappend x $i $j
    }
    # The value of x is "a d b e c f {} g"
    # There are 4 iterations of the loop.

其他说明

  • log_user 命令用来指定Expect输出的位置,默认情况下log_user的值是1,表示所有输出都放在标准输出中(一般是显示器,如果采用重定向也可以定位到文件中),如果将这个值赋值为0就表示不需要任何输出。

  • log_file 命令用来将输出记录到一个文件中去,使用格式如下:
    log_file <选项> 文件名
    选项包括下面几种:
    -open当一个文件已经被打开时,使用这个选项可以往这个文件里继续添加内容,这个选项一般用于windows系统,因为windows系统中文件是独占的,Linux系统中就不存在这个问题了。
    -leaveopen当文件已经被打开时,不继续向这个文件中添加内容。
    -noappend如果文件已存在,那么清空文件中的内容,然后再写入。
    -a如果文件已存在,则将新内容附加到当前文件的末尾。当这个命令带有文件名时,表示将spawn程序的标准输出记录到文件中,只使用log_file命令但不带文件名则表示关闭记录,这样你就可以只记录自己感兴趣的部分了。

  • remove_nulls
    expect中,默认会去掉返回中的控制符,注意:不要将控制符与空白符搞混,控制符主要是信号,他们是不会显示在屏幕上的,比如使用ctrl+c(中断)、ctrl+d(终止)等组合键发送的信号,信号是ASCII码表中01-31区间中的字符;空白符则是可以显示出来的空白符号,比如空格、回车、换行、制表等一系列符号。
    remove_nulls命令可以控制是否去掉返回中的控制符,使用方法如下:
    remove_nulls0# 关闭自动去掉控制符的功能
    remove_nulls1# 开启自动去掉控制符的功能,这是默认值

  • 含有””(和-re “.”)的模糊匹配的模式会清空输出缓冲区,不再读取从进程中输出的字符。更多关于输出缓冲区的说明

posted on 2019-12-27 10:45  进取有乐  阅读(1062)  评论(0编辑  收藏  举报

导航