expect可以实现shell实现不了的用户交互的需求。expect可以将交互写在一个脚本上,完成很多自动化的动作,比如sshftp登陆等,都是需要交互需求的。

expect是需要安装的,直接yum -y install expect安装即可。

expect的四个关键命令为:spawnexpectsendset,其中spawn调用要执行的命令expect等待命令提示信息的出现也即捕捉用户提示信息send发送需要交互的信息来替代手工的输入set则是输入变量值

1.命令格式:

1
expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile] [ args]

2.命令功能:

expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了,expect就是一套用来实现自动交互功能的软件。

 在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是expect!!!

3.工作流程:

 except的工作流程可以理解为: spawn启动进程 –> expect期待关键字 –> send向进程发送字符 –> 退出结束

4.命令参数:

1
2
-c, 从命令行执行expect脚本,默认expect是交互地执行的
-d, 可以输出输出调试信息

expect常用命令总结:

1
2
3
4
5
6
7
8
9
10
spawn               交互程序开始,后面跟命令或者指定程序
expect 获取匹配信息匹配成功则执行expect后面的程序动作
send exp_send 用于发送指定的字符串信息
exp_continue 在expect中多次匹配就需要用到
send_user 用来打印输出 相当于shell中的echo
exit 退出expect脚本
eof expect执行结束 退出
set 定义变量
puts 输出变量
set timeout 设置超时时间

5.expect语法:

5.1.spwan

spwan命令是expect的初始命令,它启动一个进程,之后所有expect操作都在这个进程中进行,其使用方法如下:

1
spwan ssh root@192.168.1.26

在spwan命令后面,直接加上要启动的进程、命令等信息,除此之外,还支持其他选项:

1
2
-open, 启动文件进程,具体说明请自行查阅
-ignore, 忽略某些信号,具体说明请自行查阅

5.2.expect

使用方法:

1
expect 表达式 动作 表达式 动作 ... ...

expect命令用于等候一个相匹配内容的输出,一旦匹配则执行expect后面的动作命令,这个命令接收几个特有参数,用的最多的就是-re,表示使用正则表达式进行匹配,如下:

1
2
spwan ssh root@192.168.1.26
expect -re ".*password" {send "root1234\r"}

expect是依附与spwan命令的,当执行ssh命令后,expect就会匹配命令执行后的输出,然后执行expect后面包含在{}中的sendexp_send动作,匹配及动作可以放在下一行,就可以省略{},如下:

1
2
3
spwan ssh root@192.168.1.26
expect -re ".*password"
send "root1234\r"

5.3.exp_send和send

exp_send是expect中的动作,send和其作用一样。exp_send命令可以发送一些特殊符号:

1
2
3
4
5
6
7
8
\r, 回车
\n, 换行
\t, 制表符
```    
send命令还有几个可选的参数:
```shell
-i, 指定spwan_id, 这个参数用来向不同的spwan_id的进程发送命令,是进行多进程控制的关键参数。
-s, s代表slowly,也就是控制发送的速度,这个参数使用的时候要与expect中的变量send_slow向关联

5.4.exp_continue

这个命令一般用在动作中,它被使用的条件比较苛刻,例子:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/expect
spwan ssh -p22 root@192.168.1.26 /usr/sbin/ifconfig eth0
set timeout 60
expect {
-timeout 1
"yes/no" { exp_send "yes\r"; exp_continue }
"*password:" { exp_send "root1234\r" }
timeout { puts "expect was timeout"; return }
}
expect eof
exit

个人理解:spwan后面的命令的输出,从第一行开始进行expect遍历匹配,若匹配则执行动作,不匹配则进行下条匹配,而exp_continue的作用是,若不匹配则跳过此行输出,并进行第二行输出进行expect的匹配

5.5.send_user

send_user用于把后面的参数输出到标准输出中去,默认的sendexp_send都是将参数输出到程序中去,用法:

1
send_user "please input password:"

这样就可以在标准输出中打印please input password:字符了。

1
2
3
4
5
#!/usr/bin/expect
if { $argc != 3 } {
send_user "usage: expect scp-expect.exp file host dir\n"
exit
}

5.6.exit

exit命令功能很简单,就是直接退出脚本,但可以利用这个命令做一些扫尾工作,如:

1
2
3
4
exit -onexit {
exec rm $tmpfile
send_user "Good Bye\n"
}

6.expect变量:

expect中有很多有用的变量,他们的使用方法与TCL中的变量相同,如:

1
2
3
4
5
6
7
8
set 变量名 变量值  # 设置变量的方法
puts $变量名 # 读取变量的方法

# define var
set file [lindex $argv 0] # 取命令行参数的
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "root1234"

7.expcct关键字:

expect中的关键字用于匹配过程,代表某些特殊含义或状态,一般用于expect命令中而不能在外面使用,也可以理解为事件,如:

1
expect eof {}

7.1.eof

eof(end-of-file)关键字用于匹配结束符,比如文件、ftp传输停止等,在这个关键字后跟上动作来做进一步的控制,特别是ftp交互操作方面,他的作用很大,如:

1
2
3
4
5
6
spawn ftp root@192.168.1.26
expect {
"password:" {exp_send "root1234"}
eof { ftp connect close }
}
interact { }

interact也是关键字,可以是当前停留在服务端,交互模式使用

7.2.timeout

timeout是expect中的一个重要变量,它是一个全局性的时间控制开关,你可以通过为这个变量赋值来规定整个expect操作的时间,注意这个变量是服务与expect全局的。例子:

1
2
3
4
set timeout 60
spawn ssh root@192.168.1.26
expect "*password:" { send "root1234\n" }
expect timeout {puts "timeout"; return }

先将超时间设置为60秒,当程序阻塞到60秒,就会激活timeout动作。

另一种设置timeout的方法,如下:

1
2
3
4
5
6
7
spwan ssh root@192.168.1.26
expect {
-timeout 60
-re "password:" {exp_send "root1234\r"}
-re "TopsecOS#" { }
timeout { puts "timeout"; return }
}

7.使用实例:

实例1:进行远程拷贝(#!/usr/bin/expect)

1.sh:

1
2
3
4
5
6
7
#!/usr/bin/expect
spawn scp log.log root@<ip>:/home/lxy
# 匹配到信息password则发送信息
expect "*password*"
# 发送密码123456
send "123456\r"
expect eof

执行:./1.sh或者expect 1.sh,不能使用sh 1.shbash 1.sh

实例2:进行远程拷贝(#!/bin/sh或者#!/bin/bash)

2.sh:

1
2
3
4
5
6
7
8
9
10
#!/bin/sh

passwd='123456'

spawn scp log.log root@<ip>:/home/lxy
# 匹配到信息password则发送信息
expect "*password*"
# 发送密码123456
send "$passwd\r"
expect eof

执行:expect 2.sh

实例3:进行远程拷贝—推荐使用此方法

3.sh:

1
2
3
4
5
6
7
8
#!/bin/sh
expect -c "
spawn scp log.log root@<ip>:/home/lxy
expect {
\"*yes/no\" { send \"yes\r\"; exp_continue }
\"*password*\" {set timeout 300; send \"123456\r\";}
}
expect eof"

执行:./3.shsh 3.shbash 3.sh

实例4:进行远程拷贝(最终版本)

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
username='root'
password='eastcom'
# 目录服务器IP
ip='127.0.0.1'

expect -c "
spawn scp log.log $username@$ip:/home/liuxy
expect {
\"*yes/no\" { send \"yes\r\"; exp_continue }
\"*password*\" {set timeout 300; send \"$password\r\";}
}
expect eof"

实例5:expect执行多条命令

1
2
3
4
5
6
7
8
9
10
11
set timeout 10

spawn sudo su - root
expect "*password*"
send "123456\r"
expect "]#*"
send "ls\r"
expect "]#*"
send "df -Th\r"
send "exit\r"
expect eof

参考

参考

参考