S_lion's Studio

expect使用

字数统计: 1.1k阅读时长: 5 min
2021/08/30 Share

使用ssh和scp时常常需要交互式的输入yes和密码,对于自动化运维中这种还需要人工点击完成的情况就比较烦了,linux的expect工具可以优雅的解决此问题。

expect是建立在tcl基础上的一个工具,可以让需要交互的任务自动化的完成,相当于是模拟用户进行交互性操作。

安装

1
$ yum install -y expect

使用方法

  1. ​ 定义脚本的执行shell,类似于bash等shell功能。
1
#!/usr/bin/expect
  1. ​ 设置超时时间,单位为秒,设置为-1意为永不超时。
1
set timeout 30
  1. ​ spawn

spawn是进入expect环境后才能执行的命令,不能直接在默认的shell环境中进行执行,主要功能是传递交互指令。

  1. ​ expect

同样是expect内部命令,判断输出结果中是否包含某个字符串,没有即立刻返回,否则就等待一段时间后退出,等待的时间由timeout指定。

  1. ​ send

发送交互值,代替我们手动输入,命令字符串后面加上\r代表敲回车。

  1. ​ interact

执行完后保持交互状态,把控制权交给控制台。

  1. ​ exp_continue

继续执行接下来的交互操作。

  1. ​ $argv

expect可以接收从bash传递的参数,可以使用[lindex $argv n],n从0开始

示例

1
2
3
4
5
6
7
8
9
10
11
[root@slions_pc1 ~]# cat interact
#!/usr/bin/expect
set timeout 30
set passwd "123"
spawn ssh 192.168.100.11
expect {
"(yes/no)" { send "yes\r",exp_continue }
"password:" { send "$passwd\r" }
}
expect "#" {send "cat /etc/sysconfig/network-scripts/ifcfg-ens33\r"}
interact

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@slions_pc1 ~]# chmod +x interact
[root@slions_pc1 ~]# ./interact
spawn ssh 192.168.100.11
root@192.168.100.11's password:
Last login: Mon Aug 30 19:34:19 2021 from 192.168.100.10
[root@slions_pc2 ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=285fd0e1-1041-4470-abc1-2c97ee6764cf
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.100.11
PREFIX=24
GATEWAY=192.168.100.2
DNS1=114.114.114.114
[root@slions_pc2 ~]# exit
登出
Connection to 192.168.100.11 closed.
[root@slions_pc1 ~]#

expect使用场景

ssh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@slions_pc1 ~]# cat expect_ssh
#!/usr/bin/expect
set timeout -1
set passwd [lindex $argv 0]
set port [lindex $argv 1]
set dest_ip [lindex $argv 2]
set cmd [lindex $argv 3]

if {$argc < 4} {
#do something
send_user "usage: $argv0 <remote_passwd> <remote_port> <remote_addr> <remote_cmd> \n"
exit
}

spawn ssh -p $port $dest_ip $cmd
expect {
"(yes/no)?"
{
send "yes\r"
expect "password:" { send "$passwd\r" }
}
"password:"
{
send "$passwd\r"
}
}
expect eof

验证

1
2
3
4
5
6
7
8
9
10
11
[root@slions_pc1 ~]# chmod +x expect_ssh
[root@slions_pc1 ~]# ./expect_ssh 123 22 192.168.100.11 'lsblk'
spawn ssh -p 22 192.168.100.11 lsblk
root@192.168.100.11's password:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 19G 0 part
├─centos-root 253:0 0 18G 0 lvm /
└─centos-swap 253:1 0 1020M 0 lvm [SWAP]
sr0 11:0 1 10G 0 rom

改用bash脚本中的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@slions_pc1 ~]# cat expect.sh
#!/bin/bash
password=$1
port=$2
dest_ip=$3
cmd=$4
/usr/bin/expect <<EOF
set timeout -1
spawn ssh -p $port $dest_ip $cmd
expect {
"(yes/no)" { send "yes\r"; exp_continue }
"password:" { send "$password\r" }
}
expect eof
EOF

scp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@slions_pc1 ~]# cat expect_scp
#!/usr/bin/expect
set timeout -1
set passwd [lindex $argv 0]
set port [lindex $argv 1]
set src_file [lindex $argv 2]
set dest_file [lindex $argv 3]

if {$argc < 4} {
#do something
send_user "usage: $argv0 <remote_passwd> <remote_port> <src_file> <dest_file> \n"
exit
}

spawn scp -P $port $src_file $dest_file
expect {
"(yes/no)?"
{
send "yes\r"
expect "*assword:" { send "$passwd\r"}
}
"*assword:"
{
send "$passwd\r"
}
}
expect "100%"
expect eof

验证

1
2
3
4
5
[root@slions_pc1 ~]# chmod +x expect_scp
[root@slions_pc1 ~]# ./expect_scp 123 22 192.168.100.11:/etc/passwd /root/192.168.100.11.passwd_file
spawn scp -P 22 192.168.100.11:/etc/passwd /root/192.168.100.11.passwd_file
root@192.168.100.11's password:
passwd 100% 1099 706.8KB/s 00:00

ssh免密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[root@slions_pc1 ~]# cat ssh.file
192.168.100.10 123
192.168.100.11 123
[root@slions_pc1 ~]# cat sshcopy.sh
#!/bin/bash
sed -ri '35a\StrictHostKeyChecking no' /etc/ssh/ssh_config
systemctl restart sshd

if [ ! -f ~/.ssh/id_rsa ]
then
ssh-keygen -P "" -t rsa -f ~/.ssh/id_rsa
fi

if [ ! -f ssh.file ]
then
echo -e "${RED_COL}请确认你的ssh.file已经生成${RESET_COL}"
break
fi

while read line
do
{
USER=`whoami`
IP=`echo $line |awk '{print $1}'`
PASSWORD=`echo $line |awk '{print $2}'`
/usr/bin/expect <<-EOF
set timeout -1
spawn ssh-copy-id $USER@$IP
expect {
"{yes/no}" { send "yes\r"; exp_continue }
"password:" { send "$PASSWORD\r" }
}
expect eof
EOF
}&
done < ssh.file
wait

CATALOG
  1. 1. 安装
  2. 2. 使用方法
  3. 3. expect使用场景
    1. 3.1. ssh
    2. 3.2. scp
    3. 3.3. ssh免密