expect是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。

expect自动交互流程:

  spawn启动指定进程---expect获取指定关键字---send向指定程序发送指定字符---执行完成退出.

expect 最关键、常用的四个命令:

命令

说明

send

用于向交互对象发送字符串

expect

从交互对象接收字符串

spawn

它主要的功能是给运行进程加个壳,用来传递交互指令

interact

执行完成后保持交互状态,把控制权交给控制台,这个时候便可以手工操作。如果没有该命令,命令完成后即退出。

   其他命令:

    exp_continue  :

    set timeout : 设置超时时间,计时单位是:秒,timeout -1 为永不超时。

    $argv 参数数组: 其中通过 [lindex $argv n] 可以获得第 n 个参数的值,调用脚本  ./xxx.sh  root   123456   192.168.199.123   分别传参数到 对应的变量

set username [lindex $argv 0] 

set password [lindex $argv 1] 

set hostname [lindex $argv 2] 

    

1. 登录远程host并且不退出

  执行用  expect  xxx.sh  或者  ./xxx.sh   ,不能用 sh xxx.sh

#!/usr/bin/expect

set timeout 5
# 跳板机1
set host "10.17.234.145"
set username "dfs"
set password "qwe200"

set host1 "39.17.121.187"
set username1 "scdd"
set password1 "qwe100"

spawn ssh  $username@$host
expect "*assword:*" {send "$password\n"}
expect "*]*" {send "ssh -p 22222 $username1@$host1\n"}
expect  "*assword*" {send "$password1\n"}
expect "*]*" {send "su\n"}
expect "*:*" {send "$password1\n"}
interact

  interact  会使得最后的 终端停留在 登录上去的 host上。

  expect 传入参数    ./xxx.sh  234

#!/usr/bin/expect
set timeout 5

set host [lindex $argv 0]

spawn ssh 192.168.199.$host

expect {
        "*yes/no*" {send "yes\r";exp_continue}
        "*assword*" {send "qwe123\r"}
}

interact  # 用这个不会退出
#expect eof  看到好多自动登录用的 这个,但是这个会 自动登出,不会停留在登录的host上。
exp_continue  附加于某个 expect 判断项之后,可以使该项被匹配后,还能继续匹配该 expect 判断语句内的其他项。我把这个理解为 类似 if,如果能匹配到前面的就 send ,不能就匹配下面的。

2. 不登录远程执行命令

  这种 看 需求的复杂情况,如果命令比较多,就写到文件再 scp 传到远程,再 ssh 远程执行。

  一般情况 看远程的安全级别,如果不高,可以 先自动设置 ssh 免密登录, 后续的 scp  ssh  都不需要 密码就可以执行。

  先看自动免密设置:

  下面的  expect -c 是 单条命令交互,暂时还没有 发现  -c 可以多条的交互,这种单条 适合 执行 一条命令。

#!/bin/bash

PORT=22
PASSWORD=qweasd

SERVERS="172.16.79.114 172.16.79.115 172.16.79.116"

## 实现免密登录配置的函数
auto_ssh_copy_id() {
    expect -c "set timeout -1;
        spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$1;       ## 这里要注意,使用'或\'不可行
        expect {
            *(yes/no)* {send -- yes\r;exp_continue;}
            **word:* {send -- $2\r;exp_continue;}
            eof {exit 0;}
        }";
}


## 循环执行,配置主机到从节点所有免密
ssh_copy_id_to_all() {
    for SERVER in $SERVERS              ## 取值需要加$
    do
        auto_ssh_copy_id $SERVER $PASSWORD
    done    
}


# ## 调用循环配置函数
# ssh_copy_id_to_all

# 然后下面就可以 操作 scp   ssh

  

  如果安全要求高,不允许免密登录的,那就只有 expect 多命令交互了。

#!/bin/bash
PORT=22
PASSWORD=qweasd

SERVERS="172.16.79.114 172.16.79.115 172.16.79.116"
for SERVER in ${SERVERS[@]}
do
    # 把命令放到文件里
  ./devconfig

  # 先 scp  传到远程
    expect -c "
    spawn scp ./devconfig root@$SERVER:/home
        expect {
            *(yes/no)* {send -- yes\r;exp_continue;}
            **word:* {send -- $PASSWORD\r;exp_continue;}
            eof {exit 0;}
        }";

  # 再 ssh 远程执行
    expect <<-EOF
    spawn ssh -p$PORT root@$SERVER
      expect {
          "*yes/no" { send "yes\r"; exp_continue }
          "*assword:" { send "$PASSWORD\r" }
      }
      expect "*#"
      send "sh /home/devconfig\r"
      expect "*#"
      send "rm -rf /home/devconfig\r"
      expect "*#"
      send "exit\r"
      expect "*#"
  EOF

done

## 这里的远程执行 也可以 采取 expect -c 单条命令执行

expect -c "
	  spawn ssh  root@$SERVER  sh /home/devconfig
          expect {
              *(yes/no)* {send -- yes\r;exp_continue;}
              **word:* {send -- $PASSWORD\r;exp_continue;}
              eof {exit 0;}
          }";