expect
- expect 是自动应答命令,用于交互式命令的自动执行。
- 借助Expect处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率 。
参数含义及说明
- spawn 是 expect 中的监控程序,其运行后会监控命令提出的交互问题
- send,发送问题答案给交互命令
- “\r”,表示回车
- exp_continue,表示当问题不存在时继续回答下面的问题
- expect eof ,表示问题回答完毕退出 expect 环境
- interact,表示问题回答完毕留在交互界面
- set NAME [ lindex $argv n ],定义变量
- set timeout -1 设置超时方式为永远等待
- set timeout 30 设置超时时间为30秒
- [lindex $argv 0] 获取expect脚本的第1个参数
- [lindex $argv 1] 获取expect脚本的第2个参数
expect 示例
- 不用expect的情况:
写一个问问题脚本:vim ask.sh
read -p "What's your name:" NAME
read -p "How old are you:" AGE
read -p "Which object you study:" OBJ
read -p "Are you happy:" FEEL
echo $NAME is $AGE\'s old study $OBJ feel $FEEL
脚本的执行需要我们一一给出答案:
现在我们写一个有问题的答案的脚本,在我们执行该脚本时会自己把答案输入重定向到文问题的脚本中。
vim answer.sh
sh /mnt/ask.sh <<-EOF
zhang
20
management
happy
EOF
但是当我们将问问题的脚本中注释掉一个问题时,再执行回答的脚本,就会出现错乱。
- 使用expect的情况:
安装expect
yum install expect -y
vim answer.exp 编写文件
#!/bin/cat
/mnt
chmod +x answer.exp
vim answer.exp
aaa
aaa
aaa
aaa
可以看到这样执行脚本中的内容都是显示出来
分开写回答
vim answer.exp
spawn sh /mnt/ask.sh
expect "name"
send "zhang\r"
expect "old"
send "20\r"
expect "object"
send "management\r"
expect "happy"
send "happy\r"
expect eof
或 interact
执行 ./answer.exp
写到一起:
#!/usr/bin/expect
set NAME [ lindex $argv 0 ]
set AGE [ lindex $argv 1 ]
set OBJ [ lindex $argv 2 ]
set FEEL [ lindex $argv 3]
spawn sh /mnt/ask.sh
expect {
"name" { send "$NAME\r" ; exp_continue }
"old" { send "$AGE\r" ; exp_continue }
"object" { send "$OBJ\r" ; exp_continue }
"happy" { send "$FEEL\r" }
}
expect of
执行
练习题
知道某一主机的密码,要求用ssh连接这台主机
vim ssh.exp
#!/usr/bin/expect
set IP [ lindex $argv 0 ]
set PASSWD [ lindex $argv 1 ]
spawn ssh root@$IP
expect {
"yes/no" { send "yes\r" ; exp_continue }
"password" { send "$PASSWD\r" }
}
interact
chmod +x ssh.exp
测试:expect ssh.exp 172.25.254.10 redhat
练习题
编写脚本显示1-10台主机里开着的主机名
思路:首先看他开着没,然后hostname显示主机名
vim hostname.sh
#!/bin/bash
Auto_SSH() 写一个函数
{
/usr/bin/expect <<-EOF
spawn ssh root@$1 hostname ##对齐写,将这些东西输入定向到expect的环境中运行
expect {
"yes/no" { send "yes\r" ; exp_continue }
"password" { send "redhat\r" } ##前面的是提取的关键字,后面发送的是答案
}
expect eof
EOF
}
for IP in {1..10}
do
ping -c1 -w1 172.25.254.$IP &> /dev/null
if [ "$?" = "0" ]
then
Auto_SSH 172.25.254.$IP | tail -n 1
fi
done
注意:
$1脚本后的第一串字符
$IP带入函数的第一串字符
执行结果:
跟我们写:
lftp 172.25.254.10 << EOF
> cd /pub
> get xxx
> EOF
的道理一样
把这些命令放到lftp的环境中运行