一、 分发系统介绍
二、 expect脚本远程登录
三、 expect脚本远程执行命令
四、 expect脚本传递参数
五、 expect脚本同步文件
六、 expect脚本指定host和要同步的文件
七、 构建文件分发系统
八、 批量远程执行命令
九、 扩展
一、 分发系统介绍
由于业务迭代更新,经常需要更改代码,如果机器很多,此时为了快速更新代码就可以使用分发系统,把更新的代码分别发布到机器上去。其中开源的上线代码的软件有很多,如git等等。这里我们使用shell来编写一个分发系统来上线代码。核心使用expect脚本语言,它可以实现远程执行命令,远程传输数据等操作。
准备工作
1.准备1台模版机器,里面是包含有最新的代码
2.每台分发机器的IP地址和密码
3.分发系统脚本
由于分发系统的核心是使用expect,因此先实践几个例子来熟悉expect的语法命令。
yum install -y expect # 可以使用yun安装expect软件
实验环境:
# 实验需要两台主机
分发主机1:192.168.1.128
远程主机2:192.168.1.138
二、 expect脚本远程登录
1. 在expect分发主机上安装expect
[root@Linux01 ~]# yum install -y expect
2. 编辑脚本
[root@Linux01 ~]# cd /usr/local/sbin/
[root@Linux01 sbin]# vim 1.expect
#!/usr/bin/expect
set host "192.168.1.138" # 设置变量,目标主机的ip
set passwd "931223" # 设置变量,目标主机的用户密码
spawn ssh root@$host # 自动交互开始,在Expect自动交互程序执行的过程中,spawn命令是一开始就需要使用的命令
expect {
"yes/no" { send "yes\r";exp_continue }
"assword:" { send "$passwd\r" } #输入密码 $passwd\r 。匹配的字符串不加p是因为不清楚是大写还是小写
}
interact
注:大括号的两边都需要有空格
// set 定义变量
// spawn 执行命令
// expect 使用expect语句进行交互
// \r表示回车
// exp_continue表示继续 expect语句
// interact表示expect脚本结束了,但还在继续交互(即停留在远程登录的主机上);也可以写成expect eof,表示停留远程机器上一会儿再退出;如果两个都不加,在登录远程主机时,直接退出
//为了让远程登录时候出现提示,可以清空/root/.ssh/known_hosts目录
3. 测试脚本
①添加执行权限
[root@Linux01 sbin]# chmod +x ./1.expect
②执行脚本
[root@Linux01 sbin]# ./1.expect
[root@zabbix-agent ~]# #进入远程主机
三、 expect脚本远程执行命令
自动远程登录,并执行命令并退出
1. 编辑脚本2.expect
[root@Linux01 sbin]# vim 2.expect
#!/usr/bin/expect
set host "192.168.1.138"
set passwd "931223"
spawn ssh root@$host
expect {
"yes/no" { send "yes\r"; exp_continue}
"assword:" { send "$passwd\r"}
}
expect "]*" # 匹配字符串 ]* *号代表通配任意字符
send "touch /tmp/exp.txt\r" # 输入命令 touch /tmp/exp.txt
expect "]*"
send "echo "expect test" > /tmp/exp.txt\r" # 输入命令 echo "expect test" >/tmp/exp.txt
expect "]*"
send "exit\r" # 输入命令 exit 退出目标主机
2. 验证
[root@Linux01 sbin]# chmod +x 2.expect #添加可执行权限
[root@Linux01 sbin]# ./2.expect
.......
再登录192.168.1.138查看文件是否创建
[root@zabbix-server ~]# cat /tmp/exp.txt
expect test
四、 expect脚本传递参数
1. 编辑脚本3.expect
[root@Linux01 sbin]# vim 3.expect
#!/usr/bin/expect
set user [lindex $argv 0] # 调用第一个参数 给变量user 用户名
set host [lindex $argv 1] # 调用第二个参数 给变量host ip
set passwd "931223"
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"
2. 测试
[root@Linux01 sbin]# chmod +x 3.expect
# 执行脚本,带上参数,第一个参数是登录目标主机的用户, 第二个参数是目标主机的ip 第三个参数是需要执行的命令
[root@Linux01 sbin]# ./3.expect root 192.168.1.138 "echo 'parameter test' >> /tmp/exp.txt"
执行完命令后,自动退出远程主机,再次登录远程主机查看文件内容是否添加
[root@Linux01 sbin]#cat /tmp/exp.txt
expect test
parameter test
五、 expect脚本同步文件
1. 编辑脚本4.expect
[root@Linux01 sbin]# vim 4.expect
#!/usr/bin/expect
set passwd "931223"
spawn rsync -av [email protected]:/tmp/exp.txt /tmp/ #核心命令,把远程主机文件同步到分发主机
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
# 当一个命令需要一定时间才能执行完的情况下,脚本最后需要加expect eof命令, 可以等待命令执行完毕才会结束脚本
# 还有在send执行的shell命令的下一行添加一个超时时间 timeout ,
# 例如: timeout 5 为5秒超时。 -1为永不超时
2. 测试
[root@Linux01 sbin]# chmod +x 4.expect
[root@Linux01 sbin]# ./4.expect
.....
[root@Linux01 sbin]#cat /tmp/exp.txt
expect test
parameter test
六、 expect脚本指定host和要同步的文件
指定目标主机和需要同步的文件, 将文件同步到目标主机上,此方式只能同步一个文件或者目录
1. 编辑脚本5.expect
[root@Linux01 sbin]# vim 5.expect
#!/usr/bin/expect
set passwd "931223"
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
2. 测试
[root@Linux01 sbin]# touch 110.txt #创建一个文件
[root@Linux01 sbin]# chmod +x 5.expect
[root@Linux01 sbin]#./5.expect 192.168.1.138 /root/110.txt # 参数使用刚才创建文件的绝对路径
....
再检查远程主机192.168.1.138的/root 目录下是否有同步过去的文件
七、 构建文件分发系统
需求背景:
对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台。所以,自动同步文件是至关重要的。
实现思路首先要有一台模板机器,把要分发的文件准备好,
然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可。
核心命令: rsync -av --files-from=list.txt / root@host:/
1.编辑rsync.expect脚本
[root@Linux01 sbin]# vim rsync.expect
#!/usr/bin/expect
set passwd "931223"
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
[root@Linux01 sbin]#chmod +x rsync.expect
2. 创建ip.list 同步机器的IP列表
[root@Linux01 sbin]#vim /tmp/ip.list
//内容如下
192.168.1.138
192.168.1.135
...
3. 创建file.list 需要同步文件的列表
[root@Linux01 sbin]#vim /tmp/file.list
//添加如下内容
/tmp/exp.txt
/tmp/test.txt
...
4. 创建 rsync.sh 脚本
[root@Linux01 sbin]#vim rsync.sh
#!/bin/bash
for ip in `cat ip.list`
do
echo $ip .
./rsync.expect $ip /tmp/file.list
done
[root@Linux01 sbin]#chmod +x ./rsync.sh
5. 测试
[root@Linux01 sbin]#./rsync.sh
...
登录ip在ip.list里的远程主机,查看文件是否同步。
注:这个文件分发系统有一个弊端,所有同步的主机都需要使用相同的密码, 而且有泄露密码的风险。
但是也可以使用密钥认证登录的方式来解决这个问题。
八、 批量远程执行命令
当同步完代码后有可能需要批量地重启服务,因此还需要批量远程执行命令,类似于自动化。
思路:创建一个执行指定命令的expect脚本, 然后使用一个shell脚本来循环执行这个expect脚本
1. 编辑exe.expect脚本
[root@Linux01 sbin]#vim exe.expect
#!/usr/bin/expect
set host [lindex $argv 0]
set passwd "931223"
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"
[root@Linux01 sbin]#chmod +x exe.expect
2. 创建 exe.sh 脚本文件,内容如下, 这里又用到了之前的 ip.list 主机列表文件
[root@Linux01 sbin]#vim exe.sh
#!/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@Linux01 sbin]#chmod +x exe.sh
3. 测试
[root@Linux01 sbin]#./exe.sh
九、 扩展
shell多线程 http://blog.lishiming.net/?p=448
(shell电子书)
shell习题做一下 http://www.apelearn.com/study_v2/chapter15.html#shll