小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;
转载于:https://blog.51cto.com/tengxiansheng/1703568