|
EXPECT 用法 expect是基于TCL的相对简单的一个免费脚本编程工具语言,用来实现自动和交互式任务进行通信,无需人的
手工干预,比如ssh\FTP等,这些程序正常情况都需要手工与它们进行交互,而使用EXPECT就可以模拟人手工交互的过程,实现自动的
和远程的程序交互,从而达到自动化的目的。
EXPECT是一个用来实现自动交互功能的软件套件(EXPECT is a software suite for automating interactive tools)
虽然,使用C、perl等一样可以实现这样的功能,而expect做的更加专业出色、简单、而且除支持unix/linux平台外,它还支持
windows平台,它就是为系统管理和软件测试方面的自动交互类需求而产生的。
2.expect程序工作流程
expect的工作流程可以理解为,spawn启动进程-->expect期待关键字---->send向进进程发送字符--->退出结束。
3.安装EXPECT软件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| [iyunv@clientC ~]# yum install expect -y
Loaded plugins: fastestmirror, refresh-packagekit
Determining fastest mirrors
* base: mirror.bit.edu.cn
* extras: ftp.sjtu.edu.cn
* updates: mirrors.hust.edu.cn
base | 3.7 kB 00:00
base/primary_db | 4.6 MB 00:00
[iyunv@clientC ~]# rpm -qa | grep expect
expect-5.44.1.15-5.el6_4.x86_64
[iyunv@clientC ~]# mkdir /scirts
[iyunv@clientC ~]# cd /scirts/
[iyunv@clientC scirts]# vi xp-excpec.exp
[iyunv@clientC scirts]# chmod 700 xp-excpec.exp
[iyunv@clientC scirts]# cat xp-excpec.exp
#!/usr/bin/expect
spawn ssh -p22 root@192.168.20.5 /sbin/ifconfig eth0
set timeout 60
expect "*password:"
send "ww123123\n"
expect eof
exit
[iyunv@clientC scirts]# ./xp-excpec.exp
spawn ssh -p22 root@192.168.20.5 /sbin/ifconfig eth0
root@192.168.20.5's password:
eth0 Link encap:Ethernet HWaddr 00:0C:29:D8:5D:8C
inet addr:192.168.20.5 Bcast:192.168.20.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fed8:5d8c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:9392 errors:0 dropped:0 overruns:0 frame:0
TX packets:2518 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:952097 (929.7 KiB) TX bytes:461897 (451.0 KiB)
|
【EXPECT语法】
Expect中的 命令是最重要的部分了,命令的使用语法如下;
命令{选项} 参数
a.1.【spawn】
spawn命令是expect的初始命令,它用于启动一个进程,之后所有expect操作都在这个进程中进行,如果
没有spawn语句,整个expect就无法执行了,spawn使用方法如下;
spawn ssh root@192.168.2.5
在spawn命令后面,直接加上要启动的进程、命令等信息,除此之外,spawn还支持其他选项如;
-open 启动文件进程,具体说明省略。
-ignore 忽略某些信号,具体说明省略。
a.2 【expect 使用方法:】
expect 表达式 动作 表达式 动作。。。。。。。
expect 命令用于等候一个相匹配内容的输出,一旦匹配上就执行expect后面的动作或命令,这个命令接受几个
特有参数,用的最多的就是-re,表示使用正则表达式的方式匹配,使用起来就像这样;
从上面的例子可以看出。expect是依附与spawn命令的,当执行ssh命令后,expect就匹配命令执行后的关键字:password:,
如果匹配到关键字就会执行后面包含在{}括号中的exp_send动作,匹配以及动作可以放在二行,这样就不需要使用{}括号了,
就像下面这样,实际完成的功能与上面是一样的;
expect 命令还有一种用法,它可以在一个expect匹配中多次匹配关键字,并给出处理动作,只需要将关键字放在一个大括号
就可以了,当然还有exp_continue.
1
2
3
4
5
| spawn ssh root@192.168.20.5
expect {
"yes/no"{exp_send "yes\r";exp_continue}
"*password:" {exp_send "123123\r"}
}
|
a.3【exp_send和send】
在上面的介绍中,我们已经看到exp_send命令的使用,exp_send命令是expect中的动作命令,它还有一个完成同样工作的
同胞:send,exp_send命令可以发送一些特殊符号,我们看到了\r(回车),还有一些其他的比如:\n(换行)、\t(制表符)等等
这些都是与TCL中的特殊符号相同。
1
2
3
4
5
| spawn ssh root@192.168.20.5
expect {
"yes/no" {send "yes\r";exp_continue}
"*password:" {exp_send "123456\r"}
}
|
send命令有几个可用的参数;
-i 指定spawn_id,这个参数用来向不同spawn_id的进程发送命令,是进行多程序控制的关键参数。
-s s代表slowly,也就是控制发送的速度,这个参数使用的时候要与expect中的变量send_slow相关联。
a.4【exp_continue】
这个命令一般用在动作中,它被使用的条件比较苛刻,看看下面的例子;
1
2
3
4
5
6
7
8
9
10
11
| #!/usr/bin/expect
spawn ssh -p22 root@192.168.20.5 /sbin/ifconfig eth0
set timeout 60
expect {
-timeout 1
"yes/no" { exp_send "yes\r";exp_continue }
"*password:" {exp_send "123456\r"}
timeout {puts "expect was timeout by xiaoping.";return}
}
expect eof
exit
|
在这个例子中,可以发现exp_continue命令的使用方法,首先它要处于一个expect命令中,然后它属于一种动作命令
完成的工作就是从头开始偏历,也就是说如果没有这个命令,匹配第一个关键字以后就会继续匹配第二关键字,但有了这个
命令后,匹配第一个关键字以后,第二次匹配依然从第一个关键字开始。
A.5【send_user】
send_user 命令用来把后面的参数输出到标准输出中去,默人的send、exp_send 命令都是将参数输出到程序中去的,
用起来就像这样;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| send_user "please input passwd:"
这个语句就可以在标准输出中打印please input passwd:字符了。
[iyunv@~]vi xp_3.exp
#!/usr/bin/expect
if { $argc != 3 } {
send_user "usage:expect scp-expect.exp file host dir\n"
exit
}
#define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "123123"
#spawn scp /etc/hosts root@192.168.20.1:/etc/hosts
spawn scp -p22 $file root@$host:$dir
expect {
"yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
timeout {puts "expect connect timeout,pls contact xp";return}
}
expect eof
exit -onexit {
send_user "xiaoping say good bye to you!\n"
}
#expect xiaoping.exp
|
【Expect 变量】
expect中有很多有用的变量,它们的使用方法与TCL语言中的变量相同,比如:
set 变量名 变量值 #设置变量的方法
puts $变量名 #读取变量的方法
1
2
3
4
5
| #define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "123123123"
|
【Expect 关键字】
expect中的特殊关键字用于匹配过程,代表某些特殊含义或状态,一般用于expect族命令中而不能在外面单独使用,
也可以理解为事件,使用上类似于:
expect eof { }
7.1 eof
eof (end-of-file)关键字用于匹配结束符,比如文件的结束符,TFP传输停止等情况,在这个关键字后跟上动作来做
进一步的控制,特别是FTP交互操作方面,它的作用很大,用一个例子看看:
1
2
3
4
5
6
| spawn FTP root@192.168.20.5
expect {
"password:" {exp_send "who am I"}
eof {ftp connet close}
}
interact {}
|
7.2 【timeout】
timeout 是expect中的一个重要变量,它是一个全局的时间控制开关,你可以通过为这个变量赋值来规定整个expectc操作的
时间,注意这个变量是服务与expect全局的,它不会纠缠某一条命令,即使命令没有任何错误,到时间依然会激活这个变量,但
这个时间到达以后除了激活一个开关之外不会做其他的事情,如何处理脚本编写人员的事情,看看它的实际使用方法:
1
2
3
4
| set timeout 60
spawn ssh root@192.168.20.5
expect "password:" {send "word\r"}
expect timeout {puts "Expect was timeout";return}
|
上面的处理中。首先将timeout变量设置为60秒,当出现问题的时候程序可能会停止下来,只要到60秒,就会激活下面的timeout
动作,这里我打印一个信息并且停止了脚本的运行,你可以做更多的其他事情,看自己的意思。
在另外一种expect格式中我们还有一种设置timeout变量的方法,看看下面的例子;
1
2
3
4
5
6
7
| spawn ssh root@192.168.20.5
expect {
-timeout 60
-re "password:" {exp_send "word\r"}
-re "Topsecos#" { }
timeout {puts "Expect was timeout";return}
}
|
在expect命令中间加上一个小横杆,也可以设置timeout变量
timeout 变量中,设置为0表示立即超时,-1则表示永久不超时。
1
2
3
4
5
6
| expect {
-timeout 20
"yes/no" {send "yes\r";exo_continue}
"*password" {send "$password\r"}
timeout {puts "expect connet timeout ,pls contact xp";return}
}
|
expect的命令行参数参考了c语言的,与bash shell有点不一样。其中,$argc为命令行参数的个数,$argv0为脚本名字本身,$argv为命令行参数。
[lrange $argv 0 0]表示第1个参数,[lrange $argv 0 4]为第一个到第五个参数。与c语言不一样的地方在于,$argv不包含脚本名字本身。
【实战1】批量分发文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| [iyunv@clientC scirts]# cat fenfa_hosts.sh
#!/bin/sh
. /etc/init.d/functions #调用fuctions函数
for ip in `cat iplist`
do
expect xp-scp.exp /etc/hosts $ip /xp >/dev/null 2>&1 #可以修改别的拷贝文件
if [ $? = 0 ];then
action "$ip" /bin/true
else
action "$ip" /bin/false
fi
done
[iyunv@clientC scirts]# cat xp-scp.exp
#!/urs/bin/expect -f
if { $argc != 3 } {
send_user "usage: expect xp-scp.exp file host dir\n"
exit
}
#define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "ww123123"
spawn scp -P22 -p $file roor@$host:$dir
set timeout 10
expect {
-timeout 2
"yes/no" {send "yes\r" ;exp_continue}
"*password:" {send "$password\r"}
timeout {puts "expect connect timeout,pls contact xp"; retur}
}
expect eof
exit
[iyunv@clientC scirts]#
|
【实战2】:使用expect实战批量分发ssh密钥文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
| [iyunv@clientC ~]# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:
2a:e1:3a:1a:b1:ec:eb:95:e5:16:d7:bb:7a:e2:88:87 root@clientC
The key's randomart image is:
+--[ DSA 1024]----+
| |
| |
| |
| . |
|. .o .S. |
|.o .+.o. . |
|o. o+o. . |
|..oEoo.. .. |
|o=oo...o+. |
+-----------------+
[iyunv@clientC ~]# cd .ssh/
[iyunv@clientC .ssh]# ls -a
. .. id_dsa id_dsa.pub
[iyunv@clientC .ssh]# grep \.ssh /etc/ss
ssh/ ssl/
[iyunv@clientC .ssh]# grep \.ssh /etc/ssh/ssh
ssh_config ssh_host_dsa_key ssh_host_key ssh_host_rsa_key
sshd_config ssh_host_dsa_key.pub ssh_host_key.pub ssh_host_rsa_key.pub
[iyunv@clientC .ssh]# grep \.ssh /etc/ssh/sshd_config
# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/bin:/usr/bin
# The strategy used for options in the default sshd_config shipped with
[iyunv@clientC .ssh]# cp id_dsa.pub id_dsa.pub.back
[iyunv@clientC .ssh]# mv id_dsa.pub .ssh/authorized_keys
mv: cannot move `id_dsa.pub' to `.ssh/authorized_keys': No such file or directory
[iyunv@clientC .ssh]# ^C
[iyunv@clientC .ssh]# mv id_dsa.pub authorized_keys
[iyunv@clientC .ssh]# ls -a
. .. authorized_keys id_dsa id_dsa.pub.back
[iyunv@clientC .ssh]# mv id_dsa
id_dsa id_dsa.pub.back
[iyunv@clientC .ssh]# mv id_dsa /xp/
[iyunv@clientC .ssh]# ls -a
. .. authorized_keys id_dsa.pub.back
[iyunv@clientC .ssh]# cd ..
[iyunv@clientC ~]# scp -P22 -p .ssh/ root@192.168.20.5:~/
The authenticity of host '192.168.20.5 (192.168.20.5)' can't be established.
RSA key fingerprint is c1:28:b4:c3:f6:3d:85:bf:b2:df:59:17:d5:9f:65:2e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.20.5' (RSA) to the list of known hosts.
root@192.168.20.5's password:
.ssh: not a regular file
[iyunv@clientC ~]# scp -P22 -p .ssh/ root@192.168.20.5:~/
root@192.168.20.5's password:
.ssh: not a regular file
[iyunv@clientC ~]# scp -P22 -p -r .ssh/ root@192.168.20.5:~/
root@192.168.20.5's password:
id_dsa.pub.back 100% 602 0.6KB/s 00:00
authorized_keys 100% 602 0.6KB/s 00:00
known_hosts 100% 394 0.4KB/s 00:00
[iyunv@clientC ~]# ^C
#HostKey /etc/ssh/ssh_host_key
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
#AuthorizedKeysFile .ssh/authorized_keys
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
# Change to yes if you don't trust ~/.ssh/known_hosts for
#PidFile /var/run/sshd.pid
Subsystem sftp /usr/libexec/openssh/sftp-server
[iyunv@clientC .ssh]# grep \AuthorizedKeysFile /etc/ssh/sshd_config
#AuthorizedKeysFile .ssh/authorized_keys
[iyunv@clientC ~]# mkdri /server/scripts -p
[iyunv@clientC scripts]# cat fenfa_sshkey.sh
#!/bin/sh
. /etc/init.d/functions
for ip in `cat iplist`
do
expect ex-ssh.exp ~/.ssh/ $ip ~/.ssh/ >/dev/null 2>&1
if [ $? = 0 ];then
action "$ip" /bin/true
else
action "$ip" /bin/false
fi
done
[iyunv@clientC scripts]#
特别提示:如果是禁止了root远程连接,那么就使用普通用户加sudo的方式在结合expect大量分发。
expect可以大量分发查询机器状态
【实战3】
[iyunv@clientC scripts]# cat ex-free.exp
#!/urs/bin/expect
if { $argc != 3 } {
send_user "usage: expect xp-scp.exp file host dir\n"
exit
}
#define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "123456"
#spawn scp -P22 -p -r $file roor@$host:$dir
spawn ssh -P22 root@$file $host $dir
set timeout 10
expect {
-timeout 10
"yes/no" {send "yes\r" ;exp_continue}
"*password:" {send "$password\r"}
timeout {puts "expect connect timeout,pls contact xp";return}
}
expect eof
exit
[iyunv@clientC scripts]# cat piliang.sh
#!/bin/bash
for ip in `cat iplist`
do
expect ex-free.exp $ip free -m
done
[iyunv@clientC scripts]# cat iplist
192.168.20.5
192.168.20.10
|
【测试】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| [iyunv@clientC scripts]# sh piliang.sh
spawn ssh -P22 root@192.168.20.5 free -m
root@192.168.20.5's password:
total used free shared buffers cached
Mem: 199 184 15 0 57 18
-/+ buffers/cache: 107 92
Swap: 1055 0 1055
spawn ssh -P22 root@192.168.20.10 free -m
ssh: connect to host 192.168.20.10 port 22: No route to host
expect: spawn id exp4 not open
while executing
"expect eof"
(file "ex-free.exp" line 20)
[iyunv@clientC scripts]#
|
~
|
|