expect
expect是用于命令行自动化交互的程序,相当于命令行版本的按键精灵。可以用来输入密码,操作程序。
- expect基于Tcl/Tk实现,在expect脚本中使用Tcl语法和支持Tcl命令。
- 通过添加Tk,你可以把命令行程序封装在Gui中。
- O'Reilly提供了一本关于Expect的书,书名为"Exploring Expect: A Tcl-Based Toolkit for Automating Interactive Applications", ISBN 1-56592-090-2.
- autoexpect 这是expect安装包提供的命令,支持录制expect脚本,录制好后稍微修改就能运行。
- shebang里面写
#!/usr/local/bin/expect −−
--的作用是给脚本传递用户参数时避免被当成expect自身的参数。脚本可以从argv里面读取用户传递的参数。 - 脚本参数在Tcl里面是
$argc $argv0 $argv
$argc表示参数个数,$argv0相当于C语言中的argv[0], $argv是一个Tcl list, 使用[lindex $argv index]
来访问。 - Tcl 变量用
set 变量名 变量值
定义。变量用$变量名
访问。 - Tcl if语句通常写法为 if { 条件 } { 条件执行内容 } elseif {条件} {执行内容} else {执行内容}
- Tcl while语句通常写法为 while { 条件} { 循环体 }
- Tcl foreach语句通常写法为
foreach 变量名 列表 { 执行内容 }
。 while循环和foreach循环支持continue 和break。
常用命令
spawn 启动要交互的应用程序
send 用于向进程发送字符串,换行符或者回车符\r 确认输入。
send_user 用来打印输出, 和tcl中puts差不多。
interact 允许用户交互
exit 退出expect脚本
eof expect执行结束
exec 执行程序
sleep 5 暂停5秒
expect 命令作用:等待,直到其中一个模式与派生进程的输出匹配,超时,或者遇到文件结尾。
expect支持多分支匹配, 用法如下
expect [pat1 body1] ... patn [bodyn]
exp_continue 在expect中多模式匹配就需要用到,允许expect本身继续执行,而不是按原样返回。
set timeout 定义expect超时的时间
一个例子:
#!/usr/bin/expect
set timeout 5
expect {
Password: {
send_user "password (for $user) on $host: "
expect_user -re "(.*)\n"
send_user "\n"
send "$expect_out(1,string)\r"
exp_continue
} incorrect {
send_user "invalid password or account\n"
exit
} timeout {
send_user "connection to $host timed out\n"
exit
} eof {
send_user \
"connection to host failed: $expect_out(buffer)"
exit
} -re $prompt
Tcl语言学习
Tcl语言介绍
- 最早称为“工具命令语言” Tool Command Language
- 跨平台
- 容易学习
- 方便图形界面编程(Tk)
- 既可以交互式执行脚本,也可以内嵌到其他程序中
- 支持事件循环
- 支持package
语法(man Tcl)
- 分号和换行分隔命令,命令和参数之间用空格/tab分割。
#
是单行注释,注释字符只有出现在一个命令开始时才有意义。 - 命令求值过程:1. 解释器把命令分解成字worlds, 完成替换。2. 第一个字是执行过程,后面的字作为执行过程的参数。
""
双引号内的内容表示一个“字”, 在引号之间的字符上会进行命令替换、变量替换、和反斜杠替换。{}
花括号内的内容表示一个“字”,花括号可以嵌套, 花括号会按照层级进行匹配。在花括号之间的字符上不进行替换,对分号、换行、右方括号、或白空格不做特殊的解释。(除了下面描述的反斜杠-换行替换之外)。字由外侧的花括号之间的字符精确的组成,不包括花括号自身。[]
方括号之间的内容Tcl进行命令替换。将递归调用Tcl解释器来把方括号中的字符作为一个Tcl脚本处理。脚本的结果将被替换到字方括号的位置。。在一个单一的字中可以有任意数目的命令替换。在由花括号包起来的字上不进行命令替换。$
开始的字,Tck会进行变量替换。支持$name
${name}
, 替换数组时用$name(index)
。index的字符将被进行命令替换、变量替换、和反斜杠替换。${name}
可以包含除了右括号之外的任何字符。一个单一的字中可以有任意数目的变量替换。在由花括号包起来的字上不进行命令替换。- 用
\
反斜线进行转义。支持的转义字符有\a \b \f \n \r \t \v \{ \} \\
。\<newline>whiteSpace
用来替换换行+空格的,整体会被替换为一个空格。 \
转义符号也支持unicode。\ooo
o是最多三个的8进制字符。\xhh
h是最多2个的16进制字符。\uhhhh
最多4个的16进制字符。这些会被替换成unicode字符。除了\<newline>whiteSpace
,其他在由花括号包起来的字上不进行反斜杠替换。- 替换不影响一个命令的字边界。例如,即使变量的值包含空格,在变量替换期间变量的整个的值成为一个单一的字的一部分。
备注
- 有个交互式解释器tclsh, 可以作为操作系统的shell使用
- 没有数字类型,可以认为只有Tck中的一切都是字worlds构成。
- 三种替换,分别是命令替换[], 变量替换$,反斜线替换。
自己瞎点评Tcl语言
- 函数传参和bash脚本一样,在进入函数前要把列表先展开,然后传递给命令,注定了效率低。
- 如果没有在参数中展开的变量,比如array这种不支持直接展开的,要在函数内用upvar命令获取上层函数的变量。使用起来不太方便。
- 不支持类型,一切都是token list,这个特点也让Tcl不能很方便的操作json等带类型的复杂数据结构。比如json里面的"100"是个字符串,转到Tcl里面类型就会丢失和100没区别。而python的json和dict互转就非常自然。
- 从语言定位来看, Tcl 应该是介于bash script和lua/python之间的编程语言。字符串处理和数据运算比bash方便,调用系统命令方便,也带json数据库网络图形界面支持,适合用来写不太复杂,但又要操作数据或者需要gui的脚本。
常用命令
- 查看Tcl命令帮助可以
man 3Tcl 命令
set 变量 值
能够设置变量的值, 无需声明变量。unset 变量
移除变量puts WORLDS
显示,支持worlds中支持变量替换
条件执行和循环
if根据条件执行脚本。使用方法if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
。前后有问号的worlds是可以省略的。
if命令把expr1作为一个表达式来求值(用与expr求值它的参数相同的方式)。这个表达式的值必须式一个boolean值(一个数值值,这里0是假而任何其他数值都是真;或者是一个字符串值,比如true或yes是真 而false或no是假);如果它是真通过把body1传递给Tcl解释器来执行它。
由于expr1 和 body1是一个表达式(worlds), 所以一般要用{}或双引号引起来传递给if。不能乱换行,换行需要在{或者"
中。
then和else是可选的“噪音词”用来使命令易读。命令的返回值是被执行的那个脚本的返回值。
- expr命令会首先用空格连接所有参数,在命令提换和变量替换后,计算表达式的值,和C语言差不多。 详见
man 3tcl expr
if { $name zhangsan } then {
puts nihao
} else {
puts hello
}
if ”$age >= 14“ then "
puts >=14
" else "
puts <14
"
if 和 { 之间要有空格,否则会被Tcl当作一个整体。
第一个if更易读。
这两个区别是用花括号时候 `$name` 是在if外面被求值。用双引号则`$age` 在if命令里面被求值(替换)。
while test body
循环。
其他流程控制
foreach
switch
continue 和break 和C语言中一样。
字符串处理
- string命令用于字符串处理
list (man 3tcl list)
list ?arg arg ...?
这个命令返回由所有arg组成的一个列表。如果未指定arg 则返回一个空串。
list 直接用原始参数来工作。例如,命令
list a b {c d e} {f {g h}}
将返回
a b {c d e} {f {g h}}
- 创建list变量的三种方法
set arr "1 2 3 4"
set arr {1 2 3 4}
set arr [list 1 2 3 4]
- list相关命令用l开头,可以在tclsh中输入l,查询list相关命令有哪些。
lappend lassign lindex linsert list llength lmap load lrange lrepeat lreplace lreverse lsearch lset lsort
- llength 获取元素个数字符串
- lrange 截取子list
- lindex 根据index获取元素
- linsert 插入
- lset 修改指定位置的元素
- lreplace 相当于字符串的replace,可以替换为0个到多个元素。
- lconat 合并list
- lappend 追加list元素
- lrepeat 把value重复N次,得到一个list
- join 相当于字符串的join。
- split 把一个字符串分离成一个Tcl列表
- lsearch 搜索list,支持严格匹配,通配符,或者正则匹配
array数组变量 (man 3tcl array)
array set arrayName list
创建array,list由偶数个元素组成,每个奇数元素被作为在array中被作为一个index对待。array get arrayName ?pattern?
成对的返回数组元素列表。array size arrayName
返回元素个数字符串glob partten
用于匹配文件路径,支持通配符*?[char]
创建命令(函数)
proc name args body
args是一个列表,可以为空,每个元素指定一个参数。每个参数指定符也可以是有一个或两个字段个列表。如果有两个字段,则第一个是参数名而第二个是参数的默认值。
文件操作
常用命令介绍
open
close
file
eof
gets
其他重要的命令
format 按sprintf格式输出
exec 调用可执行程序
source 执行脚本
info 判断变量是否存在
exit
expr
eval
incr
socket # tcp服务端客户端
encoding
dict
json
man 3tcl namespace
man 3tcl package
ls /usr/share/man/zh_CN/man3/*tcl
rpm -ql tcl
rpm -ql tcllib
rpm -ql tclx