您的位置:首页 > 运维架构 > Shell

第 三 十 二 天:shell 编 程 之 分 发 系 统 (expect)

2015-10-16 16:42 561 查看
小Q:所谓爱国心,是指你身为这个国家的国民,对于这个国家,应当比对其他
一切的国家感情更深厚。 —— 萧伯纳

=======================================================================
一:前言

如今一些比较大的企业,大都使用了负载均衡,而有时因为一些程序要更改,或者有些bug

要修改,如果仅是几台机子的话,我们把已经改好的程序拷过去,或者rsync远程推送一
下,或者网上NFS共享一下就可以了;但如果有几十台几百台,那样的方法会太繁琐,我
们此时就可以用expect来批量实现分发任务;

Expect:一个实现自动交互功能的软件套件,基于Tcl的一种脚本语言,具有简单的语法;
功 能 :实现自动登录远程机器,并自动执行命令;
和shell脚本结合,可以实现完全自动化;
注 意 :使用不带密码的密钥验证也可以实现该功能;没有密钥就只能用对方账号和密码了

安 装 :yum install -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传递过来的参数.可以使用[lindex $argv n]获得;比如:

set passwd [lindex $argv 0] 就可以在下面用$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 ssh  root@$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  [lindex $argv 0]              #定义参数数组变量
set host   "192.168.1.1"
set passwd  [lindex $argv 1]            #在bash环境下,即命令行输入,有效保护了密码
set cm [lindex $argv 2]                 #定义了一个命令变量,远程机操作的

spawn ssh $user@$host

expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"                             #上面定义的变量,也是要在本地bash环境输入
expect "]*"
send "exit\r"
执行脚本: ./1.expect root 密码 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 [lindex $argv 1]                     #定义数组参数,第2位输入,为了理解顺序
set file [lindex $argv 0]

spawn rsync -av $file root@$host:$file        #推送到远程
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
执行脚本: ./1.expect /tmp/12.txt 192.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 [lindex $argv 0]
set file [lindex $argv 1]
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 [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"
#!/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;






内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux