第 三 十 二 天:shell 编 程 之 分 发 系 统 (expect)
小Q:所谓爱国心,是指你身为这个国家的国民,对于这个国家,应当比对其他一切的国家感情更深厚。 —— 萧伯纳
=======================================================================
一:前言
如今一些比较大的企业,大都使用了负载均衡,而有时因为一些程序要更改,或者有些bug
要修改,如果仅是几台机子的话,我们把已经改好的程序拷过去,或者rsync远程推送一
下,或者网上NFS共享一下就可以了;但如果有几十台几百台,那样的方法会太繁琐,我
们此时就可以用expect来批量实现分发任务;
Expect:一个实现自动交互功能的软件套件,基于Tcl的一种脚本语言,具有简单的语法;
功 能 :实现自动登录远程机器,并自动执行命令;
和shell脚本结合,可以实现完全自动化;
注 意 :使用不带密码的密钥验证也可以实现该功能;没有密钥就只能用对方账号和密码了
安 装 :yuminstall -y excpet
二:用法
1. #!/usr/bin/expect
提示操作系统脚本内的东西是用哪个shell执行的,而expect和bash·win的cmd差不多;
注意:这一行需要在脚本的第一行。
2. set command
用来设置某些变量,或者超时时间的等;比如set user "root"设置user代表root
或者set timeout 30 30秒后断开连接 ;set timeout -l 代表永不超时
3. spawn将执行的命令或脚本
spawn是进入expect环境后才可以执行的expect内部命令,若没有装expect或者直接在
默认的SHELL下执行是无法使用的,找不到他在哪;常用的用法如下:
spawn ssh -l username 192.168.1.1 远程登录这个终端
spawn rsync -av root@192.168.1.1:/tmp/1 /tmp/将远程文件同步过来
它主要的功能是给ssh运行进程加个壳,用来传递交互指令。
4. expect "password:"
也是一个内部命令,他和shell内部命令是一样的;意思是判断上次输出结果里是否
包含“password:”的字符串,包含则立即返回,否则根据设置的时间等待;
5. send "command"
执行交互动作,即登录远程机需执行的命令;常用的有:
send "yes\r" 输入yes,\r表示回车
assword:" { send "mima\r" } 表示碰到结尾是assword字样的,输入mima后回车
6. interact
执行完成后保持交互状态,然后手动输入命令,类似于su;若没有这一句登录完成后
会退出,而不是留在远程终端上;用在登录命令后,结尾
7. $argv 参数数组
expect脚本可以接受从bash传递过来的参数.可以使用获得;比如:
set passwd 就可以在下面用$passwd调用
spawn ssh root@1.1.1.1$passwd 当执行时在后面输入密码,比密码放在文件安全
8. expect eof
标示子进程已结束的标示符;如果没有eof,可能在子进程没有结束前就退出,或是执
行完进程后待在远程终端不退出来了;
三:简单举例 (假设都是用当前目录下的1.expect脚本)
1.自动远程登录,并执行命令,登录后不退出
#! /usr/bin/expect
set host "192.168.1.1" #远程终端的IP
set passwd "123456" #远程终端root密码
spawn sshroot@$host #登录远程
expect { #子进程
"yes/no" { send "yes\r"; exp_continue} #登录后遇到yes/no字样,输入yes回车
"assword:" { send "$passwd\r" } #遇到assword字样,输入变量,回车
} ##continue继续执行进程内命令;不结束进程,类似于c中的
interact #保持交互,不退出
登陆后,执行命令然后退出的脚本:
#!/usr/bin/expect #固定用法
set user "root" #同上
set passwd "123456"
spawn ssh $user@192.168.11.18 #登录远程,没有吧IP定义为变量,效果一样
expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "$passwd\r" }
}
#登录后执行下面命令
expect "]*" #代表]#或]$,有的系统root也用]$
send "touch /tmp/12.txt\r" #碰到]*,创建文件,回车
expect "]*"
send "echo 1212 > /tmp/12.txt\r" #重定向,回车
expect "]*"
send "exit\r" #退出系统
执行脚本: ./1.expect >>> 回车
2. 传递参数
#!/usr/bin/expect
set user #定义参数数组变量
set host "192.168.1.1"
set passwd #在bash环境下,即命令行输入,有效保护了密码
set cm #定义了一个命令变量,远程机操作的
spawn ssh $user@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r" #上面定义的变量,也是要在本地bash环境输入
expect "]*"
send "exit\r"
执行脚本: ./1.expectroot 密码w
注意:数组参数的数字指代的是执行脚本输入的顺序
3. 自动同步文件
#!/usr/bin/expect
set passwd "123456"
spawn rsync -av root@192.168.11.18:/tmp/12.txt /tmp/ #rsync进行的推送
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof #子进程结束,返回本地终端
执行脚本: ./1.expect
4. 指定host和要同步的文件
#!/usr/bin/expect
set passwd "123456"
set host #定义数组参数,第2位输入,为了理解顺序
set file
spawn rsync -av $file root@$host:$file #推送到远程
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
执行脚本: ./1.expect /tmp/12.txt192.168.11.18
四:应用实例
需求:公司网站界面需要更改,更改好的程序给你了,把它分发到那几百台服务器?
思路:准备个模板机,所有服务器IP写进一个文件供调用,写个shell逐个调用IP,将调用
的IP给expect实现分发,可以用别的方法实现密码同步,先不说他了;
核心:rsync -av --files-from=list.txt/root@host:/
1.文件分发系统的实现
#!/usr/bin/expect #expect脚本
set passwd "123456"
set host
set file
spawn rsync -av --files-from=$file / root@$host:/#用来同步一批文件
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
#!/bin/bash #shell脚本,设为1.sh
for ip in `cat ip.list` #for循环
do
echo $ip #逐个打印出来供expect调用
./1.expect $ip list.txt #执行expect脚本,IP和文件对应上边的顺序
done
#IP列表文件,设为list.txt
192.168.11.18
192.168.11.19
......
此时只需执行shell脚本,就可以了;
2. 命令批量执行脚本
#!/usr/bin/expect #expect脚本,供shell脚本调用
set host
set passwd "123456"
set cm
spawn ssh root@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
#!/bin/bash #shell脚本,设为1.sh
for ip in `cat ip.list` #仍然借用了上面的IP列表文件
do
echo $ip
./1.expect $ip 'w;free -m;ls /tmp"#引号内命令对应$1,cm,如果语句够多,也可以写个
done #脚本调用,
执行只需要执行shell脚本就可以了;
===============================================================================
其实上面的这些批量操作,都是基于各个机子密码一样的情况下,不然就做不到批量了;
或者我们在生成一个密码列表文件,引入i,将IP和密码顺序一一对应,不过也是一个不小
的思路;另外我们可以给所有服务器开始的时候设一个相同的密码,但是安全性不高哈,
我们可以调用expect脚本,两天更改一个密码啊,用我们以前的的mkpasswd;
页:
[1]