Shell编程之Expect免交互

Expect概述

expect是建立在tcl语言基础上的一个工具,它可以让一些需要交互的任务自动化地完成。相当于模拟了用户和命令行的交互操作。
一个常用的场景就是批量配置集群无秘钥登录。如果集群的机器数量很多,手动一台一台地去每台机子去配置无密钥是非常糟糕的事情。使用expect功能,可以远程登录机器,并通过交互方式进行无秘钥登录。

Expect安装

挂载光盘
制作本地yum源
执行安装命令:yum install expect -y

Expect基本命令

send:向进程发送字符串,用于模拟用户的输出
expect:expect的一个内部命令,判断上次输出结果里是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回。
spawn:启动进程,并跟踪后续交互信息
interact:执行完后保持交互状态,把控制权交给控制台
EOF:结束
Timeout:指定超时时间,过期则继续执行后续指令
​单位是秒
​timeout -1 为永不超时
​默认情况下,timeout是10秒
exp_continue
允许expect继续向下执行命令
send_user
回显命令,相当于echo
$argv参数数组
Expect脚本可以接受从bash传递的参数,可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个。。。。参数
Expect脚本必须以interact或者expect eof结束,执行自动化任务通常expect eof就够了
expect eof是在等待结束标志。由spwan启动的命令在结束时会产生一个eof标记,expect eof即在等待这个标记。

Expect执行方式

直接执行

ssh免交互远程连接

#!/usr/bin/expect
#超时时间
set timeout 20
log_file test.log
log_user 1
#参数传入
set hostname [lindex $argv 0]
set password [lindex $argv 1]
#追踪命令
spawn ssh root@$hostname
#捕捉信息并且匹配,免交互执行
expect {
        "(yes/no)"
        {send "yes\r";exp_continue}
        "*password"
        {send "$password\r"}
}
#控制权交给控制台执行
interact

脚本执行结果

[root@localhost opt]# chmod +x a.sh 
[root@localhost opt]# ./a.sh 192.168.131.129 123123 
spawn ssh root@192.168.131.129
root@192.168.131.129's password: 
Last login: Thu Oct 10 18:56:11 2019 from 192.168.131.133
[root@localhost ~]#

嵌入执行

ssh免交互远程连接

#!/bin/bash
   hostname=$1
   password=$2
   /usr/bin/expect<<-EOF
   spawn ssh root@${hostname}
   expect {
          "(yes/no)"
          {send "yes\r";exp_continue}
          "*password"
          {send "$password\r"}
  }
  expect "*]#"
  send "exit\r"
  expect eof
EOF

脚本执行结果

[root@localhost opt]# chmod +x b.sh 
[root@localhost opt]# ./b.sh 192.168.131.129 123123 
spawn ssh root@192.168.131.129
root@192.168.131.129's password: 
Last login: Thu Oct 10 18:56:02 2019 from 192.168.131.133
[root@localhost ~]# exit
登出
Connection to 192.168.131.129 closed.
[root@localhost opt]#

Expect案例

创建用户tom,密码tom123

#!/bin/bash
hostname=$1
password=$2
useradd $hostname
expect <<-EOF
spawn passwd $hostname
expect "新的*"
send "$password\r"
expect "重新输入*"
send "$password\r"
expect eof;
EOF
[root@localhost opt]# chmod +x c.sh 
[root@localhost opt]# ./c.sh tom tom123
spawn passwd tom
更改用户 tom 的密码 。
新的 密码:
无效的密码: 密码少于 7 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[root@localhost opt]# 

SSH远程登录脚本健壮版
在ssh远程登录无法连接到时,不会输出报错信息。

#!/usr/bin/expect
set timeout 20 //超时时间
log_file test.log
log_user 1
set hostname [lindex $argv 0] //参数传入
set password [lindex $argv 1]
spawn ssh root@$hostname //追踪命令
expect { //捕捉信息并且匹配,免交互执行
"Connection refused" exit
"service not known" exit
"(yes/no)"
{send "yes\r";exp_continue}
"*password"
{send "$password\r"}
}
interact //控制权交给控制台执行
exit