工作中遇到批量服务器无交互情况,但又不能使用秘钥免密,尴尬了。百度了一下无交互命令expect,做个笔记分享。
安装
yum方式安装
yum -y insatll
tar包方式安装
expect安装需要tcl依赖。
tcl源码包:https://sourceforge.net/projects/tcl/files/latest/download
expect源码包:https://sourceforge.net/projects/expect/files/latest/download
日常应用expect为两种方法:
- 1.独立expect脚本应用
- 2.shell嵌套expect命令
第一种应用:独立expect脚本
制作独立的expect脚本,一般以exp作为后缀名。
1)定义脚本执行的shell:
#!/usr/bin/expect
2)set timeout(expect的内部命令)
设置超时时间,单位是秒,值为-1时 永不超时(当远端命令执行时间较长时,需要注意此参数,譬如日志分割操作,会占用较长时间,可用到此参数)。
如30秒:timeout 30
3)spawn (expect的内部命令)
功能:传递交互指令
4)expect(expect的内部同名命令)
主要功能:判断输出是否包含某项字符,没有立即返回(如果设置有timeout值,则等待timeout时间)
5)send(expect的内部命令)
功能:执行交互动作(就是远端要执行的命令!)
命令字符串后面加“r”,表示换行,就如同我们敲完命令会有回车操作
6)interact(expect的内部命令)
执行完毕后保持交互状态,把控制权交给当前控制台。
如果不加这一项,交互完成退出。
7)exp_continue (expect的内部命令)
继续接下来的交互操作
8)$argv (expect的内部命令)
expect脚本接受从bash传递过滤的参数
格式:[ llindex $argv n ] ,n从0开始,表示第一、二、三。。。个参数
注:以上参数中expect(内置命令)
如果以{}方式交互,可以理解为组,但只打印第一个send结果
如果想实现每个expect交互命令都有打印结果需要expect独立send命令
范例一:实现获取远端主机名、日期等,然后返回源主机
创建 ssh1.exp,关注以下几点,
1.使用set配置固定值(密码明文,不够安全)
2.expect判断字符“]*”,中*是通配符
3.send命令中“\r”,r代表回车,换行。
4.$默认引用的当前脚本变量,如果牵涉远程命令需要\$转义!
#!/usr/bin/expect
#定义变量
set IPADD "192.168.68.150"
set USER "root"
set PWD "123456789"
set timeout -1
#spawn传递交互命令
spawn ssh $USER@$IPADD
#
expect {
"yes/no" { send "yes\r" }
"password:" { send "$PWD\r" }
}
#expect判断包含"]*"就触发send交互动作,*为通配符!
#获取远端主机名
expect "]*" {send "hostname\r"}
#获取远端主机IP($1中$需要转义,否则会被认为是变量!!!)
expect "]*" {send "hostname -I|awk '{print \$1}'\r"}
#获取远端主机时间
expect "]*" {send "date +%F_%T\r"}
#退出远端主机
expect "]*" { send "exit\r" }
测试结果:
范例二:与范例一获取信息一样,不同点在于变量值在控制台输入!
使用$avgr调用追加变量
#!/usr/bin/expect
set IPADD [ lindex $argv 0 ]
set USER [ lindex $argv 1 ]
set PWD [ lindex $argv 2 ]
set timeout 30
spawn ssh $USER@$IPADD
expect {
"yes/no" { send "yes\r" }
"password:" { send "$PWD\r" }
}
#保持交互,留着当前控制台
interact
测试结果:
第二种应用:shell脚本中使用expect
在shell脚本中,expect使用EOF执行
如下脚本:用于服务器批量spc文件到远端家目录
(如暴露主机信息,可使用gpg进行脚本加密,或者将主机信息移到单独文件进行gpg,我这里只是为了演示写在一个脚本里了)
#!/bin/bash
#实现批量服务器scp传输文件到远端家目录
#只需更新SCPFILE文件路径及主机信息
#要传送的文件
SCPFILE=~/check.sh
#主机信息
echo "
#IPADD USER PWD
192.168.68.100 root 123456789
192.168.68.150 root 123456789
"| grep -Ev "^#|^$" >/tmp/host.txt
########################################################
SUM=`cat /tmp/host.txt |wc -l`
for i in `seq $SUM`
do
IPADD=`sed -n "$i"p /tmp/host.txt|awk '{print $1}'`
USER=`sed -n "$i"p /tmp/host.txt |awk '{print $2}'`
PWD=`sed -n "$i"p /tmp/host.txt |awk '{print $3}'`
#scp传送巡检脚本
expect <<EOF
set timeout -1;
spawn scp $SCPFILE $USER@$IPADD:
expect {
"yes/no" { send "yes\n" ; exp_continue }
"password:" { send "$PWD\n" }
}
expect eof
EOF
echo "=========$IPADD SCP完成 ================="
done
rm -f /tmp/host*
——————————————————————————–
在shell脚本中,使用expect -c ” “
使用-c双引号代替EOF,但因为是双引号做标识符,使在引号内的特殊符号都需要使用\反斜杠对特殊符号进行转义,不是很方便,不喜欢。。。
#!/bin/bash
echo start
expect -c "
spawn ssh root@$192.168.68.100
expect \"password:\" { send \"123456789\r\" }
interact
"
发表评论