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 “.”)的模糊匹配的模式会清空输出缓冲区,不再读取从进程中输出的字符。更多关于输出缓冲区的说明