使用expect来解决命令交互问题
目录
linux里面很多命令都是需要人为交互的,对于做成脚本来说,有点不合适了,比如通过密码连接SSH必须要在控制台输入密码(安全起见还是用rsa key),expect
是预期的意思,它可以实现我们预期的结果。
安装
-
ubuntu/debian
sudo apt install -y expect
-
centos/rhel
sudo yum install -y ecpect
解释器使用expect
#!/usr/bin/expect
set IP [lindex $argv 0] # 读取第1个参数设置为 IP 变量
set PASSWD [lindex $argv 1] # 读取第2个参数设置为 PASSWD 变量
set CMD [lindex $argv 2] # 读取第3个参数设置为 CMD 变量
spawn ssh $IP $CMD # spawn 来给命令加壳,以便于断言输出
expect { # expect 是断言命令
# 如果读取到屏幕上输出 (yes/no) 信息,则输入 "yes" 并按下回车键
# exp_continue 是继续等待花括号内的断言, 如果不加这一句会直接跳出 expect
"(yes/no)?" { send "yes\r"; exp_continue }
"password:" { send "$PASSWD\r" } # 如果读取到屏幕上输出 password 信息,则输入 PASSWD 变量中的内容
"*host " { exit 1 } # 如果读取到 "No route to host" 等内容, 就以非0状态退出
}
expect eof # 等待命令执行结束
这种方式由于解释器使用了expect,所以只能使用有限的命令,不是很推荐
解释器使用bash
假设certbot不支持非交互使用
#!/bin/bash
sudo expect << EOF
spawn certbot --nginx
expect {
"Enter email address" { send "iuxt@qq.com\n";exp_continue}
"Please read the Terms of Service" {send "A\n";exp_continue}
"Would you be willing to share your email address" {send "N\n";exp_continue}
"Which names would you like to activate HTTPS for" {send "\n";exp_continue}
"You have an existing certificate that has exactly the same domains" {send "1\n";exp_continue}
"Please choose whether or not to redirect HTTP traffic to HTTPS" {send "2\n";exp_continue}
eof
}
直接使用expect命令
这种和切换解释器类似, 类比于
./test.sh
和bash test.sh
的关系。
vim test.sh
spawn ldapadd -x -D cn=Manager,dc=nutstore,dc=com -W -f /vagrant/basedomain.ldif
expect {
"Enter LDAP Password:" {send "com.012\n";exp_continue}
eof
}
expect test.sh