Expect 主要应用于自动化交互式操作场景,可以将ssh、ftp、scp等需人工交互的操作写在一个脚本上使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率。

其主要交互流程是:

spawn启动指定进程(发送命令) -> expect获取指定关键字 -> send发送回应 -> 执行完成 -> 继续或退出.

一、 下载安装

expect 是由基于Tcl( Tool Command Language )语言开发的,因此安装前需要安装tcl语言环境。可以使用yum安装或源码安装。

1. 下载

2. yum安装

yum install -y tcl
yum install -y expect

3. rpm安装

rpm -ivh tcl-8.4.13-4.el5.x86_64.rpm
rpm -ivh expect-5.43.0-5.1.x86_64.rpm

4. 源码安装

解压安装包

tar -zxvf tcl8.4.20-src.tar.gz
tar -zxvf expect5.45.3.tar.gz

安装tcl

cd tcl8.4.20/unix/
./configure --prefix=/usr/tcl --enable-shared
make
make install
cp tclUnixPort.h ../generic

安装expect

cd /root/expect5.45.3/
./configure --prefix=/usr/expect --with-tcl=/usr/tcl/lib --with-tclinclude=/root/tcl8.4.20/generic
make
make install
ln -s /usr/tcl/bin/expect /usr/bin/expect

简单测试

[root@mydb02 ~]# expect
expect1.1> send "hello world\n"
hello world

expect1.1> expect "hi" { send "You said hi\n" } \
+> "hello" { send "Hello yourself\n" } \
+> "bye" { send "That was unexpected\n" }
#输入
hi
#输出
You said hi

二、 expect 常用命令

完整版可执行 man expect 查看

命 令说 明
spawn启动新的交互进程,后面跟命令或者指定程序
expect待匹配信息(部分匹配即可)。从进程中接收信息,如果匹配成功,就执行expect后的动作
send向进程发送字符串或命令
exp_continue匹配多个字符串在执行动作后加此命令
send_user打印后跟的字符串内容,相当于shell中的echo
interact执行完命令后保持在交互状态,此时Expect会把控制权交给控制台,变回手工操作。如果只是登录过去执行一段命令就退出,可将其改为 expect eof
exit退出expect脚本
eofexpect执行结束, 退出
set定义变量
puts输出变量
set timeout设置超时时间

三、 常用脚本

最简单的自动登录脚本

#!/usr/bin/expect

set timeout 30
spawn ssh -l root 172.16.22.131
expect "password*"
send "123456\r"
interact
# 或者 expect eof 

#!/usr/bin/expect 必须位于第一行,说明需要使用系统的哪个脚本解析引擎来执行,具体路径根据实际expect 命令实际路径而定。

1. 使用变量

#!/usr/bin/expect
set ip 172.20.110.199
set user root
set password 123456wht 
set timeout 10 
spawn ssh $user@$ip
expect "password:"
send "$password\n"
interact
#expect eof

运行结果如下

[root@localhost ~]#./sshbl.exp 
spawn ssh 172.20.110.199
root@172.20.110.199's password: 
Last login: Sat May 12 11:26:45 2018 from 172.20.110.169
[root@localhost ~]# 

2. 位置参数

#!/usr/bin/expect 
set ip [lindex $argv 0] 
set user [lindex $argv 1] 
set password [lindex $argv 2] 
spawn ssh $user@$ip 
expect { 
 "yes/no" { send "yes\n";exp_continue } 
 "password" { send "$password\n" } 
} 
interact
#运行  ./ssh3.exp 192.168.8.100 root magedu

3. shell脚本调用expect

批量ssh-copy-id

#!/bin/bash
#用于批量ssh-copy-id 免密码登陆服务器
which expect || yum -y install expect
TXT_PATH=/home/wht/ssh-login/list.txt

ssdzd(){
expect <<-EOF 
set timeout 10 
spawn ssh-copy-id  $user@$ip 
expect { 
   "yes/no" { send "yes\n";exp_continue } 
   "password" { send "$password\n" } 
} 
expect "]#" { send "exit\n" } 
expect eof 
EOF
}
a=`cat ${TXT_PATH}|wc -l`
echo $a
for i in `seq $a` ; do
  echo $i
  ip=`cat ${TXT_PATH}|head -n $i|tail -n 1|awk '{print $1}'`
  user=`cat ${TXT_PATH}|head -n $i|tail -n 1|awk '{print $2}'`
  password=`cat ${TXT_PATH}|head -n $i|tail -n 1|awk '{print $3}'` 
  ssdzd
done

list.txt

  • 192.168.8.27 root zmoam#11232134
  • 192.168.8.31 root zmoam#11231234

4. 自动mv文件

vi  exe.expect

#!/usr/bin/expect
set host [lindex $argv 0]
set passwd "xxxx"
spawn ssh myuser@$host
expect { 
 "yes/no" { send "yes\n";exp_continue } 
 "password" { send "$passwd\n" } 
} 
expect "$ "
send "sudo -i\r"
expect "myuser:"
send "$passwd\r"
expect "]# "
send "cd /etc/zabbix/zabbix_agentd.d/zabora/sql\r"
expect "]# "
send "mv test.txt test.txt.bak\r"
expect "]# "
send "exit\r"
#expect eof
expect "~]$ "
send "exit\r"
expect eof

vi  test.sh

#!/bin/bash
for ip in `cat ip.txt`
do
    ./exe.expect $ip
done

ip.txt

  • 192.168.3.225
  • 192.168.3.247

执行效果

[root@mydb02 ~]# ./test.sh ip.txt 
spawn ssh myuser@192.168.3.225
myuser@192.168.3.225's password: 
Last login: Wed Dec  2 19:07:49 2020 from 10.13.3.224
[myuser@mydb03 ~]$ sudo -i
[sudo] password for myuser: 
[root@mydb03 ~]# cd /etc/zabbix/zabbix_agentd.d/zabora/sql
[root@mydb03 sql]# mv test.txt test.txt.bak
[root@mydb03 sql]# exit
logout
[myuser@mydb03 ~]$ exit
logout
Connection to 192.168.3.225 closed.
spawn ssh myuser@192.168.3.247
myuser@192.168.3.247's password: 
Last login: Wed Dec  2 19:07:50 2020 from 10.13.3.224
[myuser@mydb04 ~]$ sudo -i
[sudo] password for myuser: 
[root@mydb04 ~]# cd /etc/zabbix/zabbix_agentd.d/zabora/sql
[root@mydb04 sql]# mv test.txt test.txt.bak
[root@mydb04 sql]# exit
logout
[myuser@mydb04 ~]$ exit
logout
Connection to 192.168.3.247 closed.
[root@mydb02 ~]#

5. 执行需要多次应答的脚本

执行 perl adcfgclone.pl dbTechStack  脚本,并输入各种各样的应答

#!/bin/bash

#**********************************************************************************
# Author: Hehuyi_In
# Date: 2022年05月
# FileName: erp_adcfgclone_db_tier.sh
# Dependence: yum install expect -y
# Description: Run adcfgclone.pl script on db tier
# CopyRight (C): 2022 All rights reserved
# example: bash -x erp_adcfgclone_db_tier.sh or ./erp_adcfgclone_db_tier.sh
#**********************************************************************************


ORACLE_SID_UPPER=`echo "$ORACLE_SID" | tr '[:lower:]' '[:upper:]'`

# execute adcfgclone.pl script by expect
erp_adcfgclone_db_tier(){
lsnrctl stop $ORACLE_SID
cd /u01/$ORACLE_SID/db/tech_st/11.2.0/appsutil/clone/bin

expect <<EOF
set timeout -1
spawn perl adcfgclone.pl dbTechStack 
expect "APPS password :"
send "xxxxx\r"
expect "Target System Hostname"
send "\r"
expect "RAC (y/n)"
send "\r"
expect "Database SID :"
send "$ORACLE_SID\r"
expect "Base Directory :"
send "/u01/$ORACLE_SID\r"
expect "Directory List :"
send "/tmp\r"
expect "Target System"
send "2\r"
expect "DATA_TOP Directory 1 :"
send "/u01/$ORACLE_SID/db/apps_st/data/${ORACLE_SID_UPPER}/onlinelog\r"
expect "DATA_TOP Directory 2 :"
send "/u01/$ORACLE_SID/db/apps_st/data/${ORACLE_SID_UPPER}/datafile\r"
expect "/u01/$ORACLE_SID/db/tech_st/11.1.0"
send "/u01/$ORACLE_SID/db/tech_st/11.2.0\r"
expect "preserve the Display"
send "n\r"
expect "Target System Display"
send "\r"
expect "source system (y/n)"
send "n\r"
expect "Port Pool"
send "80\r"
EOF
}

# execute the function
erp_adcfgclone_db_tier

参考

shell编程之expect用法

教你如何在Linux中通过expect工具实现脚本的自动交互 | 《Linux就该这么学》

expect简单教程 - zbk.gyl - 博客园

expect脚本同步文件、批量远程执行命令_rain_yunlx的博客-CSDN博客

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐