expect 是进行高效的系统和网络管理工作是不可或缺,实现自动交互的一种工具.
1.
#!/usr/bin/expect -f
-f 参数指定从哪个文件中读取命令。当被用在#!指示(见上)中时此参数是可选的,
所以其它参数可在命令行中提供.
-i 参数使expect交互地提示输入命令,而不是从文件中读命令。命令提示行通过exit命令或一个eof字符
结束。
cmd arg arg arg : 一条Tcl命令由空格分割的单词组成. 其中, 第一个单词是命令名称, 其余的是命令参数 .
$foo : $符号代表变量的值. 在本例中, 变量名称是foo.
[cmd arg] : 方括号执行了一个嵌套命令. 例如, 如果你想传递一个命令的结果作为另外一个命令的参数, 那么你使用这个符号 .
"some stuff" : 双引号把词组标记为命令的一个参数. "$"符号和方括号在双引号内仍被解释 .
{some stuff} : 大括号也把词组标记为命令的一个参数. 但是, 其他符号在大括号内不被解释.
斜线符号() 是用来引用特殊符号. 例如:n 代表换行. 反斜线符号也被用来关闭"$"符号 , 引号,方括号和大括号的特殊含义 .
可以通过-d参数调试Expect脚本: # /usr/bin/expect -d sample_login.exp user passwd
2.
expect <set timeout 3600
spawn strace -o /dev/null ssh
EOF
expect的timeout时间, timeout是以秒为单位, 如果设置为0, 是根本就不等待, 设置为-1, 是永远等待.
spawn: 运行你需要交互的程序,后面跟上命令名和命令参数
expect {
"yes/no" { send "yes/r";exp_continue }
"password:" {send "$password\r"}
}
send 向进程发送字符串。
expect 等待进程的某些字符串。
expect $prompt
脚本中的exp_continue命令的作用是用来继续expect . 如果在脚本中没有这个命令,
当输入完成“yes”后,expect已经返回,它会“expect $prompt”,它就没有机会输入密码。
在expect中调用了exp_continue相当于让脚本的又重新从expect处开始运行,有点类似于while或者for循环。
只是在这里没有判断条件。因此,在刚开始写expect脚本的时候,很容易就出现了死循环。----相当于shell,c中的continue。
3.
spawn command 命令调用,激活一个Unix程序来进行交互式的运行。
嵌套命令
set LOGIN [ lindex $argv 0 ]
set PASS [ lindex $argv 1 ]
一个Tcl函数lindex来实现的,该函数从列表/数组得到一个特定的元素。
[ ]用来实现将函数lindex的返回值作为set命令的参数。
命令行参数:$argc,$argv 0,$argv 1 ... $argv n
$argc 是指脚本在命令行有几个参数。
4.顺序和循环
if { } {
exit 1 |0
}
for语句的格式有点类似这样:
for { set i 0} {$i < 10} { incr i} {puts $i}
case $variable {
$var1 { }
$var2 { }
$var3 { }
}
while ( ){
}
5.运算
incr 增加
6.函数定义和调用
proc function_name { $argv } {
....
}
在proc里面直接return(后面没有带参数), 那么proc将会直接返回, 不会返回任何值.
否则, 将会返回最后一条语句的执行结果的返回值.
exit在任意的地方都能够退出tclsh的执行程序, 返回到shell.
例子:
proc do_console_login {login pass} {
set timeout 5
set done 1
set timeout_case 0
while ($done) {
expect {
"console login:" { send "$login\n" }
"Password:" { send "$pass\n" }
"#" {
set done 0
send_user "\n\nLogin Successfully...\n\n"
}
timeout {
switch -- $timeout_case {
0 { send "\n" }
1 {
send_user "Send a return...\n"
send "\n"
}
2 {
puts stderr "Login time out...\n"
exit 1
}
}
incr timeout_case
}
}
}
}
proc do_exec_cmd {} {
set timeout 5
send "\n"
expect "#"
send "uname -p\n"
expect "#"
send "ifconfig -a\n"
expect "#"
send "exit\n"
expect "login:"
send_user "\n\nFinished...\n\n"
}
if {$argc<2} {
puts stderr "Usage: $argv0 login passwaord.\n "
exit 1
}
set LOGIN [lindex $argv 0]
set PASS [lindex $argv 1]
spawn telnet 10.13.32.30 7001
do_console_login $LOGIN $PASS
do_exec_cmd
close
exit 0
7. expect的default 相当于匹配了timeout和eof
8. expect的spawn了一个process, 如果结束了, 它会返回给expect一个eof信号,
反过来, expect也可以主动来关闭spawn的process, 这时候,process也会看到一个eof信号,
一般来说, process收到这个信号后, 它会主动关闭它自己.
9. 使用expect的re来匹配正则表达式, 那使用什么来表示glob匹配呢? 默认的就是使用glob来匹配,
也可以使用显式的-gl来声明使用glob.假如要匹配一些expect的关键字,
例如eof, default, timeout等, 就可以使用-re或者-gl来表示.
如果在使用glob的时候, 如果匹配的pattern里面有变量,
最好加上-gl, 防止由于变量的值为expect的关键字或者标志.
expect -re "\[(.*)]:"
if {$expect_out(1,string)!="/bin/tcsh"} {
send "/bin/tcsh" }
send " "
expect eof
1.)第一个expect命令现在使用了-re参数,这个参数表示指定的的字符串是一个正则表达式,而不是一个普通的字符串。
2.) 在一个正则表达时中,可以在()中包含若干个部分并通过expect_out数组访问它们。
各个部分在表达式中从左到右进行编码,从1开始(0包含有整个匹配输出)。
3.) 当发现一个匹配则检查包含在[]中的字符串,查看是否为/bin/tcsh .
4.)在进行expect匹配的时候, 使用-nocase参数, nocase是将字符串转换成小写来进行匹配.
10
#!/usr/bin/expect -f
set timeout 10
expect " " {
set raw $expect_out(buffer)
# remove final carriage return
set response [string trimright "$raw" " "]
}
expect命令就等待输出中出现回车字符。如果在超时之前得到回车符,
那么set命令就会将用户输入的内容赋值给变脸raw。
随后的命令将用户输入内容最后的回车符号去除以后赋值给变量response。
11. 输入和输出
输入:send
输出:puts stderr | stdout " \n" | puts " "
expect_user 从标准输入读取数据.
expect_tty和expect_user的区别, expect_user能够被shell所重定向.
而expect_tty则是永远指从键盘读取输入. send_tty和send_user的 情况类似.
12.字符串应该用引号括起来:
% set str "test"
'test'
要输出一个标量的内容,使用put语句:
% puts $str
test
$用来说明str是一个变量。puts函数在标准输出显示变量的内容。
13. sleep是expect的一个标准命令,表示暂停若干秒钟。
break , continue
#!/usr/bin/expect
spawn ftp
while {1} {
expect "ftp>"
send "ip_address\r"
expect {
"Connected" break
"refused" { sleep 10} ;
}
}
14.一个简单实用例子脚本
#!/usr/bin/expect
foreach IP {
192.168.0.2
192.168.0.3
.............
} {
#循环,可以多台相同密码的服务器同时处理
spawn strace -o /dev/null ssh
#strace 信号追踪,直到命令执行完成,信号才会结束.避免一时连接不上,反复使用SSH连接.
expect {
"*(yes/no)*" { send "yes\r"}
"password:" { send "123456\r" }
} #SSH第一次远程登录服务器
expect "username"
send "su -\r" #SSH普通用户名密码登录
expect "Password:"
send "123456\r" #SSH的root用户名密码登录
expect -timeout 1
expect "root"
send "route add -net 10.1.1.0 netmask 255.255.255.0 gw 10.1.1.1\r"
}
#expect -timeout sec 表示以后的对话,在sec秒完成后自动退出.
#route add 添加一条路由
#一般退出expect脚本:send "quit\r" 或者send "exit\r"
阅读(1830) | 评论(0) | 转发(0) |