expect 是一个用来实现自动交互功能的软件,是基于tool command Language脚本语言的编程工具。
在现今的企业运维中, 自动化运维已经成为运维的主流趋势,
但是在很多情况下,执行系统命令或程序时,系统会以交互式的形式要求运维人员输入指定的字符串,之后才能继续执行命令。
例如为用户设置密码时,一般情况下就需要手工输入2次密码。
# 可以使用yun安装expect软件
yum install -y expect
# 实验需要两台主机
# 主机1:10.1.1.32 主机2:10.1.1.30
自动远程登录脚本
# 1.expect 脚本文件内容如下
#!/usr/bin/expect
set host "10.1.1.30" # 设置变量,目标主机的ip
set passwd "123456" # 设置变量,目标主机的密码
spawn ssh root@$host # 自动交互开始,在Expect自动交互程序执行的过程中,spawn命令是一开始就需要使用的命令
expect { # expect命令用于匹配交互信息,输入争正确的交互内容。
"yes/no" { send "yes\n";exp_cuntinue } #匹配出现 "yes/no" 的行,{输入yes\n,\n就是换行符,} #exp_countinue 表示继续匹配,只要不是交互过程的最后一行都要在后后面加上这个命令
"assword:" { send "$passwd\n" } #输入密码 $passwd\n 。匹配的字符串不加p是因为不清楚是大写还是小写
}
interact #interact表示expect脚本结束了
# 注: 大括号的两边都需要有空格
测试脚本是否可用
# 先给脚本加上执行权限
chmod 755 1.expect
# 执行脚本
[root@shell ~]> ./1.expect
spawn ssh root@10.1.1.30
root@10.1.1.30's password:
Last login: Tue Jul 31 23:40:29 2018 from 10.1.1.170
[root@zabbix-server ~]#
# 可以正常登陆到目标主机就算成功了
自动登陆后,执行命令后退出
# 2.expect 脚本文件的内容如下
#!/usr/bin/expect
set host "10.1.1.30"
set passwd "123456"
spawn ssh root@$host
expect {
"yes/no" { send "yes\n"; exp_continue}
"assword:" { send "$passwd\n"}
}
expect "]*" # 匹配字符串 ]* *号代表通配任意字符
send "touch /tmp/ecpect.txt\r" # 输入命令 touch /tmp/ecpect.txt 这里命令结尾的\r 与前面的\n效果类似
expect "]*"
send "echo "expect test" > /tmp/ecpect.txt\r" # 输入命令 echo "expect test" >/tmp/ecpect.txt
expect "]*"
send "exit\r" # 输入命令 exit 退出目标主机
测试脚本效果
# 老规矩 加执行权限
[root@shell ~]> chmod 755 2.expect
# 执行脚本 后边的全是自动输入的
[root@shell ~]> ./2.expect
spawn ssh root@10.1.1.30
root@10.1.1.30's password:
Last login: Fri Aug 3 00:54:02 2018 from 10.1.1.32
[root@zabbix-server ~]# touch /tmp/expect.txt
[root@zabbix-server ~]# echo 'expect test' > /tmp/expect.txt
[root@zabbix-server ~]# [root@shell ~]> 最后退出了10.1.1.30 回到到了当前的主机
# 再次登录10.1.1.30 查看文件是否创建OK
[root@shell ~]> ./1.expect
spawn ssh [email protected]
[email protected]'s password:
Last login: Fri Aug 3 01:10:51 2018 from 10.1.1.32
[root@zabbix-server ~]# cat /tmp/expect.txt
expect test
# 文件内容没问题。
传递参数
# 3.expect 脚本文件内容如下
#!/usr/bin/expect
set user [lindex $argv 0] # 调用第一个参数 给变量user 用户名
set host [lindex $argv 1] # 调用第二个参数 给变量host ip
set passwd "123456"
set cm [lindex $argv 2] #调用第三个参数 给变量cm 需要执行的命令
spawn ssh $user@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
测试脚本效果
# 加执行权限
[root@shell ~]> chmod 755 3.expect
# 执行脚本,带上参数,第一个参数是登录目标主机的用户, 第二个参数是目标主机的ip 第三个参数是需要执行的命令
[root@shell ~]> ./3.expect root 10.1.1.30 "echo 'parameter test' >> /tmp/expect.txt"
spawn ssh root@10.1.1.30
root@10.1.1.30's password:
Last login: Fri Aug 3 01:13:59 2018 from 10.1.1.32
[root@zabbix-server ~]# echo 'parameter test' >> /tmp/expect.txt
[root@zabbix-server ~]# [root@shell ~]>
#再次执行脚本 执行的命令是查看目标主机下 /tmp/expect.txt 的文件内容
[root@zabbix-server ~]# [root@shell ~]> ./3.expect root 10.1.1.30 "cat /tmp/expect.txt"
spawn ssh [email protected]
[email protected]'s password:
Last login: Fri Aug 3 01:27:07 2018 from 10.1.1.32
[root@zabbix-server ~]# cat /tmp/expect.txt
expect test
parameter test
自动同步文件
# 4.expect 脚本文件内容
#!/usr/bin/expect
set passwd "123456"
spawn rsync -av root@10.1.1.30:/tmp/expect.txt /tmp/ #核心命令
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
# 当一个命令需要一定时间才能执行完的情况下,脚本最后需要加expect eof命令, 可以等待命令执行完毕才会结束脚本
# 还有在send执行的shell命令的下一行添加一个超时时间 timeout ,
# 例如: timeout 5 为5秒超时。 -1为永不超时
测试脚本效果
[root@shell ~]> chmod 755 4.expect
[root@shell ~]> ./4.expect
spawn rsync -av root@10.1.1.30:/tmp/expect.txt /tmp/
root@10.1.1.30's password:
receiving incremental file list
expect.txt
sent 43 bytes received 123 bytes 110.67 bytes/sec
total size is 27 speedup is 0.16
# 查单本地的/tmp目录下是否有expect.txt文件
[root@shell ~]> cat /tmp/expect.txt
expect test
parameter test
# 同步成功
指定目标主机和需要同步的文件, 将文件同步到目标主机上,此方式只能同步一个文件或者目录
# 5.expect 脚本文件内容
#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0] #第一个参数指定目标主机的ip
set file [lindex $argv 1] #第二个参数指定要同步的文件或目录, 必须要使用绝对路径。
spawn rsync -av $file root@$host:$file
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
测试脚本效果
# 创建一个目录,然后在目录下创建一个文件 用户测试
[root@shell ~]> mkdir testdir
[root@shell ~]> touch testdir/testfile.txt
# 执行脚本
[root@shell ~]> chmod 755 5.expect
[root@shell ~]> ./5.expect 10.1.1.30 /root/testdir/ #参数使用刚才创建目录的绝对路径
spawn rsync -av /root/testdir/ root@10.1.1.30:/root/testdir/
root@10.1.1.30's password:
sending incremental file list
created directory /root/testdir
./
testfile.txt
sent 113 bytes received 74 bytes 374.00 bytes/sec
total size is 0 speedup is 0.00
# 检查10.1.1.30 的/root 目录下是否有同步过去的文件
[root@zabbix-server ~]> tree /root/
/root/
├── anaconda-ks.cfg
└── testdir
└── testfile.txt
1 directory, 2 files
# 同步成功
需求背景:
对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台。所以,自动同步文件是至关重要的。
实现思路首先要有一台模板机器,把要分发的文件准备好,
然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可。
核心命令: rsync -av –files-from=list.txt / root@host:/
定义用于同步文件的expect脚本
# rsync.expect 脚本文件内容
#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -avR --files-from=$file / root@$host:/ # R选项可以在目标主机中不存在同步的目录时自动创建相关目录
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
创建一个存放文件路径的列表文件
# files.list 文件的内容如下:
/root/111/111.txt
/data/wwwroot/222.txt
/tmp/2333.txt
创建列表文件中的相关文件,用于实验
[root@shell ~]> mkdir /root/111
[root@shell ~]> mkdir /data/wwwroot/ -p
[root@shell ~]> touch `cat files.list`
创建一个主机IP列表文件
# ips.list文件内容如下,这里我就用一台主机来做实验了,这个文件中可以放多个主机的IP
10.1.1.30
创建一个循环同步的shell脚本
# rsync.sh 脚本文件内容如下:
#!/bin/bash
for ip in `cat ips.list`
do
echo $ip
./rsync.expect $ip files.list
done
测试脚本效果
# 给脚本文件执行权限
[root@shell ~]> chmod 755 rsync.sh rsync.expect
# 执行脚本 rsync.sh
[root@shell ~]> ./rsync.sh
10.1.1.30
spawn rsync -av --files-from=./files.list / [email protected]:/
root@10.1.1.30's password:
building file list ... done
data/
data/wwwroot/
data/wwwroot/222.txt
root/
root/111/
root/111/111.txt
tmp/
tmp/2333.txt
sent 344 bytes received 88 bytes 864.00 bytes/sec
total size is 0 speedup is 0.00
# 查看10.1.1.30主机上是否有刚才同步过去的文件
[root@zabbix-server ~]> ls -dl /data/wwwroot/222.txt /root/111/111.txt /tmp/2333.txt
-rw-r--r--. 1 root root 0 8月 3 11:47 /data/wwwroot/222.txt
-rw-r--r--. 1 root root 0 8月 3 11:47 /root/111/111.txt
-rw-r--r--. 1 root root 0 8月 3 11:47 /tmp/2333.txt
# 同步成功
注:这个文件分发系统有一个弊端,所有同步的主机都需要使用相同的密码, 而且有泄露密码的风险。
但是也可以使用密钥认证登录的方式来解决这个问题。
思路:创建一个执行指定命令的expect脚本, 然后使用一个shell脚本来循环执行这个expect脚本
创建 exe.expect 脚本文件,内容如下
#!/usr/bin/expect
set host [lindex $argv 0]
set passwd "123456"
set cm [lindex $argv 1]
spawn ssh root@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
创建 exe.sh 脚本文件,内容如下, 这里又用到了之前的 ips.list 主机列表文件
#!/bin/bash
for ip in `cat ip.list` # 遍历主机IP列表
do
echo $ip
./exe.expect $ip "w;free -m;df -h" 执行exe.expect脚本, 指定主机ip 和需要执行的命令
done
测试脚本效果
[root@shell ~]> ./exe.sh
10.1.1.30
spawn ssh root@10.1.1.30
root@10.1.1.30's password:
Last login: Fri Aug 3 10:16:16 2018 from 10.1.1.128
[root@zabbix-server ~]# w;free -h;df -h
12:27:53 up 2:36, 3 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root tty1 09:52 1:58m 0.05s 0.05s -bash
root pts/0 10.1.1.1 10:03 2:33 0.05s 0.05s -bash
root pts/1 10.1.1.128 12:27 0.00s 0.03s 0.02s w
total used free shared buff/cache available
Mem: 976M 138M 437M 6.8M 400M 646M
Swap: 2.0G 0B 2.0G
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root 27G 1.1G 26G 4% /
devtmpfs 478M 0 478M 0% /dev
tmpfs 489M 0 489M 0% /dev/shm
tmpfs 489M 6.8M 482M 2% /run
tmpfs 489M 0 489M 0% /sys/fs/cgroup
/dev/sda1 1014M 125M 890M 13% /boot
tmpfs 98M 0 98M 0% /run/user/0
# 执行成功
shell多线程