Shell expect
使用场景
expect介绍
示例
使用场景:
在进行命令行操作时,会遇到一些命令执行的中途需要手动输入。比如使用git 克隆、上传、下载命令中需要输入账号与密码,比如执行远程拷贝需要输入密码等。
以上场景日常使用频率过高,每次输入内容高度一致,可使用expect交互命令,把账号密码保存到脚本中,每次执行脚本,让脚本自动输入,减少手动负担
expect介绍
expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了expect就是一套用来实现自动交互功能的软件需要自行安装
yum install -y expect
expect基础
在使用expect时,基本上都是和以下四个命令打交道:
命令 | 作用 |
---|---|
spawn | 启动新的进程 |
expect | 从进程接收字符串,信息匹配成功则执行expect后面的程序动作 |
send | 用于向进程发送字符串 |
interact | 允许用户交互,与expect eof作用类似,但结束交互后,所处位置为脚本内最后所在位置 |
set | 定义变量 |
set timeout | 设置超时时间 |
exp_continue | 相当于其他语言的continue,此处用于判断语句,在此处重新进行判断 |
expect eof | 表示结束交互,但会原终端所在位置。 |
exit | 退出expect脚本 |
- spawn 命令用来启动新的进程,spawn后的expect和send命令都是和使用spawn启动的新进程进行交互。
- expect 通常用来等待一个进程的反馈,我们根据进程的反馈,再使用send命令发送对应的交互命令。
- send 命令接收一个字符串参数,并将该参数发送到进程。
- interact 命令用的其实不是很多,一般情况下使用spawn、expect和send命令旧可以很好的完成我们的任务;但是在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。比如我们使用spawn、send和expect命令完成了ssh登录south主机,但是我们希望登录成功后,仍然可以停留在south主机命令行状态,以便手动的执行后续命令,此时使用interact命令就可以很好的完成这个任务。
总结expect自动应答的基本步骤
第一步: 运行一个程序或命令=> spawn 命令信息
第二步: 识别产生信息关键字=> expect 捕获关键字 {send 应答信息}
第三步: 根据识别关键做处理=> send 应答信息
expect实现ssh非交互登录
#!/usr/bin/expect
# expect脚本,需要使用expect $0 方式执行
# 开启一个新的会话
spawn ssh south@192.168.128.200
# 期望出现什么
# send 发送一个信息
# exp_continue 如果没有yes/no 则跳过
expect {
"yes/no" { send "yes\r"; exp_continue } # \r 回车`man tr`
"password" { send "123456\r" };
}
# 停在新会话中,不输入会再次回到旧会话
interact
[root@nan ~]# expect expect01.expect
spawn ssh south@192.168.128.200
The authenticity of host '192.168.128.200 (192.168.128.200)' can't be established.
ECDSA key fingerprint is SHA256:gUWWp+3dSGCUjHZIWfCsCO0X3lsDo9Yl/ZUY9qRqQ34.
ECDSA key fingerprint is MD5:1c:3b:ac:14:d9:86:66:ca:fa:2c:9e:c1:68:eb:68:45.
Are you sure you want to continue connecting (yes/no)? yes # 非交互输入yes
Warning: Permanently added '192.168.128.200' (ECDSA) to the list of known hosts.
south@192.168.128.200's password: # 非交互输入密码
Last login: Mon Jun 13 12:14:44 2022 from 192.168.128.200
[south@nan ~]$
设置变量
#!/usr/bin/expect
# expect脚本,需要使用expect $0 方式执行
# 设置变量
set ip 192.168.128.200
set user south
set passwd 123456
# 设置超时时间
set timeout 5
# 开启一个新的会话
spawn ssh ${user}@${ip}
# 期望出现什么
# send 发送一个信息
# exp_continue 如果没有yes/no 则跳过
expect {
"yes/no" { send "yes\r"; exp_continue } # \r 回车`man tr`
"password" { send "${passwd}\r" };
}
# 停在新会话中,不输入会再次回到旧会话
interact
设置变量
#!/usr/bin/expect
# expect脚本,需要使用expect $0 方式执行
# 设置变量
# 设置位置参数,相当于shell中的$1
set ip [lindex $argv 0]
set user [lindex $argv 1]
set passwd 123456
# 设置超时时间
set timeout 5
# 开启一个新的会话
spawn ssh ${user}@${ip}
# 期望出现什么
# send 发送一个信息
# exp_continue 如果没有yes/no 则跳过
expect {
"yes/no" { send "yes\r"; exp_continue } # \r 回车`man tr`
"password" { send "${passwd}\r" };
}
# 停在新会话中,不输入会再次回到旧会话
#interact
# 出现 '#' 号,执行以下命令
expect "#"
send "useradd nanaaa\r"
send "pwd\r"
send "exit\r"
# 结束交互
expect eof
expect expect03.expect 192.168.128.200 south
scp非交互传输文件
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set passwd 123456
set timeout 5
spawn scp /etc/hosts ${user}@${ip}:/tmp
expect {
"yes/no" { send "yes\r"; exp_continue }
"password" { send "${passwd}\r" };
}
expect eof
实现批量主机公钥推送
#!/bin/bash
> ip.txt
rpm -q expect
if [ $? -ne 0 ];then
yum -y install expect
fi
if [ ! -f ~/.ssh/id_rsa ];then
ssh-keygen -P "" -f ~/.ssh/id_rsa
fi
for i in 180
do
{
IP=192.168.128.180
ping -c1 $IP &>/dev/null
if [ $? -eq 0 ];then
echo "$IP is up..." | tee -a ip.txt
/usr/bin/expect <<-EOF
spawn ssh-copy-id root@192.168.128.180
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "123456\r" }
}
expect eof
EOF
fi
}&
done
wait
echo "finish....."
注意:ssh-copy-id 后的IP 必须满足输入yes和password两个条件,否则会导致spawn会话没有被成功开启
报错:
expect: spawn id exp6 not open
while executing
"expect eof"