expect

目录

   平时维护服务器都需要登录堡垒机,而且堡垒机是动态密码的,这给我维护带来很多不方便。所以只有先登录堡垒机,然后在一台跳板机上
去操控其他的服务器,如果遇到要同时改配置文件的情况,服务器上又不能随便安装自动化程序,所以只有用默认的expect,在大多数情况下,
expect还是能满足要求的。

示例脚本

#!/usr/bin/expect -f                                                                                                                                                 
#这个脚本的功能是切换为root执行命令然后退出
set ip [lindex $argv 0]
set password [lindex $argv 1 ]
set password1 [lindex $argv 2 ]
set action [lindex $argv 3 ]
set timeout 10  

spawn ssh $ip

#输入密码
expect "*password:" { send "$password\r"}

#登录后切换为root用户
expect "*]*" { send "su -\r"}

#这样一段是兼容各种情况,在切换root后出现的字符可能是一下3种可能
expect "*密码*" { send "$password1\r"} \
       "*口令*" { send "$password1\r"} \
       "*Password*" { send "$password1\r"}

#执行命令
expect "*]#" { send "$action\r"}

#执行完后退出
expect "*]#" { send "exit\r"}

#如果退出后继续退出
expect "exit" { send "exit\r"}
interact

上面的脚本实现了一个自动登录主机并切换为root用户去执行命令,然后退出主机这样的功能,可以用于批量执行命令

需要根据你的实际情况去改一下脚本,下面对这个脚本做一个简单的分析。

  expect脚本执行的逻辑是这样的:expect 模式 动作, 就是当遇到模式时就自动执行后面的动作,如果一个模式可能有多种情况
我们就可以这样写 expct 模式1 动作 模式2 动作 ... 我们上面为了兼容不同主机输入密码的写法就是这样的。还有就是expect
脚本的模式匹配总是从上到下的依次匹配的。
  只要理解了expect的工作模式,你就可以很轻松的写出自动脚本来。

使用方法

我把上面那个脚本写入一个名为expsshroot.exp的文件里,在其他的shell脚本里调用,如下的shell脚本

#!/bin/bash
#hostfile是文件的地址,里面写要执行命令的ip                                                                                                                                                                         
hostfile=$1
#输入普通用户密码,使用read来读取密码,而不是直接把密码写在文件里,这样安全一些
read -s -p "password:" password
#输入root密码
read -s -p "password1:" password1
for i in `cat ${hostfile}`
do
  ./expsshroot.sh  "${i}" "${password}" "${password1}" 'touch test'
done

问题

  上面的脚本虽然可以很轻松的批量执行命令,但是却存在一个严重的安全问题,那就是执行expsshroot.sh时另外开启了一个进程,这时如果你ps -ef |grep ssh
就可以看到两个密码了,这样太不安全了。

解决方法

  对于上面的问题,我们能想到的最直接的解决方法就是,要是是shell内部调用expect,而不是外部调用脚本的方法(实现内部调用的方法有HERE Document,source code
,exec),内部调用ps -ef是看不见的。恩,我们就这么干
脚本如下:
#!/bin/bash                                                                                                                                                              
#这个脚本是HERE Document的解决方案
hostfile=$1

read -s -p "password:" password
read -s -p "password1:" password1

function expsshroot
{
expect <<-EOF
set timeout 10  
spawn ssh $1
expect "*password:" { send "$2\r"}
expect "*]*" { send "su -\r"}
expect "*密码*" { send "$3\r"} \
"*口令*" { send "$3\r"} \
"*Password*" { send "$3\r"}
expect "*]#" { send "$4\r"}
expect "*]#" { send "exit\r"}
expect "exit" { send "exit\r"}
interact
expect eof
EOF
}

for i in `cat ${hostfile}`
do
 expsshroot  "${i}" "${password}"  "${password1}" 'touch test'
done
#这样在执行是就不能用ps -ef 过滤来看见密码了

还是有问题

  这样的确可以执行命令了,但是我们却看不见命令执行的过程。

目录