关于 Tcl 和 Expect 的语法,请参考 Unix/Linux 平台任务的自动化相关部分。
QUOTE:
例 1: 下面是一个 telnet 到指定的远程机器上自动执行命令的 Expect 脚本, 该脚本运行时的输出如下:
# /usr/bin/expect sample_login.exp root 111111
spawn telnet 10.13.32.30 7001
Trying 10.13.32.30...
Connected to 10.13.32.30.
Escape character is ‘^]‘.
accho console login: root
Password:
Last login: Sat Nov 13 17:01:37 on console
Sun Microsystems Inc. SunOS 5.9 May 2004
#
Login Successfully...
# uname -p
sparc
# ifconfig -a
lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index
1
inet 127.0.0.1 netmask ff000000
eri0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2
inet 10.13.22.23 netmask ffffff00 broadcast 10.13.22.255
ether 0:3:ba:4e:4a:aa
# exit
accho console login:
Finished...
ChinaUnix 论坛 Shell 版精华帖合集 - Made by UNREGISTERED version of Easy CHM
382
QUOTE:
下面是该脚本的源代码:
# vi sample_login.exp:
proc do_console_login {login pass} {
set timeout 5
set done 1
set timeout_case 0
while ($done) {
expect {
"console login:" { send "$loginn" }
"Password:" { send "$passn" }
"#" {
set done 0
send_user "nnLogin Successfully...nn"
}
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 -pn"
ChinaUnix 论坛 Shell 版精华帖合集 - Made by UNREGISTERED version of Easy CHM
383
expect "#"
send "ifconfig -an"
expect "#"
send "exitn"
expect "login:"
send_user "nnFinished...nn"
}
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
上面的脚本只是一个示例,实际工作中,只需要重新实现 do_exec_cmd 函数就可以解决类似问题了。
我们看一看这样的一个例子脚本:
#! /usr/bin/expect
spawn ftp 202.199.248.11
expect "Name"
send "ftpr"
expect "Password:"
send "nothingr"
expect "apply"
send "cd /pub/UNIX/Linux/remoteXr"
expect "successful."
send "binr"
expect "set to I"
send "get exceed5.zipr"
expect "complete."
send "quitr"
ChinaUnix 论坛 Shell 版精华帖合集 - Made by UNREGISTERED version of Easy CHM
394
这个是什么意思?呵呵,就是个自动下载程序。第一行说明这个程序应该调用/usr/b
in/expect 去执行,然后的就是 expect 命令。
我们可以把建立连接
的命令放在一个循环里面,并且根据回应的不同自动选择重新输入命令还是继续执行:
spawn ftp
while {1} {
expect "ftp>"
send "o 202.199.248.11r"
expect {
"Connected" break
"refused" { sleep 10} ;
}
ChinaUnix 论坛 Shell 版精华帖合集 - Made by UNREGISTERED version of Easy CHM
396
}
这里使用了我们在 tcl 语言中讲到的 while 和 break 命令,熟悉 C 的读者应该很容易看出
它的行为:不断地等待 ftp>提示符,在提示符下面发送连接远端服务器的命令,如果服
务器回应是 refused(连接失败) ,就等待 10 秒钟,然后开始下一次循环;如果是 Conne
cted,那么就跳出循环执行下面的命令。sleep 是 expect 的一个标准命令,表示暂停若干
秒钟。
gawk ‘/foo/ {print $0}‘ BBS-list
实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜
寻输入档里的每一行是否含有子字串 ‘foo‘,如果含有 ‘foo‘ 则执行 action。
action 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。
#删除一个文件中前 10 行
sed ‘1,10d‘
# delete the last line of a file
#删除一个文件中最后 1 行
sed ‘$d‘
#删除一个文件中最后 2 行
sed ‘N;$!P;$!D;$d‘
#删除一个文件中后 10 行
sed -e :a -e ‘$d;N;2,10ba‘ -e ‘P;D‘ # method 1
sed -n -e :a -e ‘1,10!{P;N;D;};N;ba‘ # method 2
#删除文件所有空白行(似于"grep ‘.‘ ")
sed ‘/^$/d‘ # method 1
sed ‘/./!d‘ # method 2
#删除文件开头部分中的所有空白行
sed ‘/./,$!d‘
#打印一个文件的后 10 行(仿"tail")
sed -e :a -e ‘$q;N;11,$D;ba‘
sed ‘$!N;$!D‘
输出文件最后 2 行,相当于 tail -2 foo
# 在每一行中查找字串“foo”,并将找到的“foo”替换为“bar”
sed ‘s/foo/bar/‘ # 只替换每一行中的第一个“foo”字串
sed ‘s/foo/bar/4‘ # 只替换每一行中的第四个“foo”字串
sed ‘s/foo/bar/g‘ # 将每一行中的所有“foo”都换成“bar”
sed ‘s/\(.*\)foo\(.*foo\)/\1bar\2/‘ # 替换倒数第二个“foo”
规则
表达式 描述
/./ 将与包含至少一个字符的任何行匹配
/../ 将与包含至少两个字符的任何行匹配
/^#/ 将与以 ‘#‘ 开始的任何行匹配
/^$/ 将与所有空行匹配
/}^/ 将与以 ‘}‘(无空格)结束的任何行匹配
/} *^/ 将与以 ‘}‘ 后面跟有零或多个空格结束的任何行匹配
/[abc]/ 将与包含小写 ‘a‘、‘b‘ 或 ‘c‘ 的任何行匹配
/^[abc]/ 将与以 ‘a‘、‘b‘ 或 ‘c‘开始的任何行匹配
当编辑指令(参照[section 2.2])在命令列上执行时 , 其前必须加上选项 -e 。其命令格式如下 :
sed -e ‘编辑指令 1‘ -e ‘编辑指令 2‘ ... 文件檔
首先理解一个()的情况
举个例子:
[[email protected] root]# echo "111(222)333"| sed ‘s/(\(.*\))/\1\1/‘
111222222333
因为(\(.*\)只有这一个部分,所以\1 就意味着这一个部分提取两次(如果是\2 就应该提不到东西)
[[email protected] root]# echo "111(222)333"| sed ‘s/(\(.*\))/\1\2/‘
sed:-e 表达式 #1,字符 16:Invalid reference \2 on `s‘ command‘s RHS
由于(不是元字符,所以直接写(就表示(这个符号,而\(才表示包含什么的意思
而又因为是()里面的内容,所以将 222 提取两次
如果将()去掉,例如
[[email protected] root]# echo "111(222)333"| sed ‘s/\(.*\)/\1\1/‘
111(222)333111(222)333
那么提取的匹配就是这个部分了
-------------------------------------
[[email protected] root]# echo "111(222)333"| sed ‘s/\(.*\)(\(.*\))/\1\1\1/‘
111111111333
因为//里面是由\(.*\) 和 (\(.*\))两部分组成,而\1 仍然是提取第一部分,也就是(222)前的所有内容
和(222)这个整个部分替换为(222)前的所有内容提取三次,其后的 333 不变
[[email protected] root]# echo "111(222)333"| sed ‘s/\(.*\)(\(.*\))/\2\2\2/‘
ChinaUnix 论坛 Shell 版精华帖合集 - Made by UNREGISTERED version of Easy CHM
696
222222222333
将(222)前的所有部分和(222)看成一个整体,被替换为()内的部分,也就是 222。
此处理解\2\2\2,2 的含义应该是提取第二个\(.*\)即:“第二个包含” 得意思也就是: (将()换成 yy 也
是一样得含义)
[[email protected] root]# echo "111y222y333"| sed ‘s/\(.*\)y\(.*\)y/\2\2\2/‘
222222222333