• 20.31 expect脚本同步文件
  • 20.32 expect脚本指定host和要同步的文件
  • 20.33 构建文件分发系统
  • 20.34 批量远程执行命令

  • 扩展:
  • shell多线程 http://blog.lishiming.net/?p=448

    20.31 expect脚本同步文件

  • 在一台机器上把文件同步到多台机器上
  • 自动同步文件
    
    [root@aming-01 ~]# cd /usr/local/sbin
    [root@aming-01 sbin]# ls
    1.expect  2.expect  3.expect  check_ng.sh  lvs_dr.sh  lvs_nat.sh  mon  nginx_logrotate.sh
    [root@aming-01 sbin]# vi 4.expect

#!/usr/bin/expect
set passwd "123456"
spawn rsync -av root@192.168.202.132:/tmp/12.txt /tmp/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof

~

:wq

- 加上执行权限,再来执行脚本

[root@aming-01 sbin]# vi 4.expect
[root@aming-01 sbin]# chmod a+x 4.expect
[root@aming-01 sbin]# ./4.expect

[root@aming-01 sbin]# ./4.expect 
spawn rsync -av root@192.168.202.132:/tmp/12.txt /tmp/
root@192.168.202.132's password: 
receiving incremental file list
12.txt

sent 30 bytes received 84 bytes 228.00 bytes/sec
total size is 5 speedup is 0.04
[root@aming-01 sbin]#

[root@aming-01 sbin]# cat /tmp/12.txt
1212
[root@aming-01 sbin]#

- 如果把脚本里面的 expect eof 注释掉会有什么样的差异

[root@aming-01 sbin]# vi 4.expect
[root@aming-01 sbin]# ./4.expect 
spawn rsync -av root@192.168.202.132:/tmp/12.txt /tmp/
root@192.168.202.132's password: [root@aming-01 sbin]# rm -f /tmp/12.txt
[root@aming-01 sbin]# ./4.expect 
spawn rsync -av root@192.168.202.132:/tmp/12.txt /tmp/
root@192.168.202.132's password: [root@aming-01 sbin]#

[root@aming-01 sbin]# ls /tmp/12.txt
ls: 无法访问/tmp/12.txt: 没有那个文件或目录
[root@aming-01 sbin]#

- 还没来得及传输就退出了,仅仅是输入完密码,就停止了,者与肯定不对
- 所以需要加上expect eof (表示最起码能给你足够的时间去做一些操作,比如传输文件的时候,需要反应一会儿,)如果不加这个,有可能仅仅是登录就退出来,或者没有登录成功,

# 20.32 expect脚本指定host和要同步的文件
- set timeout 定义超时时间(单位为 秒) -1 为永远不超时
- 可以指定具体的秒数,比如5秒

[root@aming-01 sbin]# vi 3.expect

#!/usr/bin/expect

set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "123456"
set cm [lindex $argv 2]
spawn ssh $user@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]"
send "$cm\r"
set timeout 5
expect "]
"
send "exit\r"











:wq
[root@aming-01 sbin]# ./3.expect root 192.168.202.132 "vmstat 1"
spawn ssh root@192.168.202.132
root@192.168.202.132's password: 
Last failed login: Wed Nov 29 21:56:17 CST 2017 from 192.168.202.130 on ssh:notty
There were 10 failed login attempts since the last successful login.
Last login: Wed Nov 29 19:52:32 2017 from 192.168.202.1
[root@aming-02 ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 169360 876 280408 0 0 25 5 66 130 0 0 99 0 0
0 0 0 169360 876 280440 0 0 0 4 72 138 0 0 100 0 0
0 0 0 169360 876 280440 0 0 0 0 79 135 0 0 100 0 0
0 0 0 169360 876 280440 0 0 0 0 60 122 0 0 100 0 0
0 0 0 169360 876 280440 0 0 0 8 77 138 0 1 99 0 0
[root@aming-01 sbin]#

- 如果是set timeout -1 就是永久了

expect "]"
send "$cm\r"
set timeout -1
expect "]
"
send "exit\r"

~

:wq
[root@aming-01 sbin]# vi 3.expect 
[root@aming-01 sbin]# ./3.expect root 192.168.202.132 "vmstat 1"
spawn ssh root@192.168.202.132
root@192.168.202.132's password: 
Last login: Wed Nov 29 22:17:40 2017 from 192.168.202.130
[root@aming-02 ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
9 0 0 169484 876 280460 0 0 25 5 66 130 0 0 99 0 0
0 0 0 169484 876 280444 0 0 0 0 63 125 0 0 100 0 0
0 0 0 169484 876 280444 0 0 0 0 66 118 1 1 98 0 0
0 0 0 169484 876 280444 0 0 0 0 58 113 0 0 100 0 0
0 0 0 169484 876 280444 0 0 0 0 61 115 0 0 100 0 0
^C[root@aming-01 sbin]#

- 只能手动ctrl c 结束

- 指定host和要同步的文件

[root@aming-01 sbin]# vi 5.expect

#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -av $file root@$host:$file
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof














:wq

- 先把之前的那个文件同步过来再来执行这个脚本

[root@aming-01 sbin]# vi 4.expect

#!/usr/bin/expect
set passwd "123456"
spawn rsync -av root@192.168.202.132:/tmp/12.txt /tmp/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
~



"4.expect" 8L, 173C

[root@aming-01 sbin]# vi 4.expect
[root@aming-01 sbin]# ./4.expect
spawn rsync -av root@192.168.202.132:/tmp/12.txt /tmp/
root@192.168.202.132's password: 
receiving incremental file list
12.txt

sent 30 bytes received 84 bytes 76.00 bytes/sec
total size is 5 speedup is 0.04

-  先加上执行权限,然后下面执行我们的脚本

[root@aming-01 sbin]# chmod a+x 5.expect
[root@aming-01 sbin]# ./5.expect 192.168.202.132 "/tmp/12.txt"
spawn rsync -av /tmp/12.txt root@192.168.202.132:/tmp/12.txt
root@192.168.202.132's password: 
sending incremental file list

sent 31 bytes received 12 bytes 86.00 bytes/sec
total size is 5 speedup is 0.12
[root@aming-01 sbin]#


# 20.33 构建文件分发系统
- 需求背景 
- 对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台。所以,自动同步文件是至关重要的。
-  实现思路
- 首先要有一台模板机器,把要分发的文件准备好,然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可。
-  核心命令
- rsync -av --files-from=list.txt / root@host:/
- 使用rsync 的 –files参数,可以实现调用文件里面的列表,进行多个文件远程传输,进而实现文件分发 文件列表的路径必须要以全局路径,绝对路径

- 文件分发系统的实现

[root@aming-01 sbin]# vi rsync.expect

#!/usr/bin/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


:wq


- 现在root 下面创建 目录111.下面创建222,在下面创建一个lll.txt

[root@aming-01 ~]# ls /root/111/
[root@aming-01 ~]# cd 111
[root@aming-01 111]# mkdir 222
[root@aming-01 111]# cd 222
[root@aming-01 222]# ls
[root@aming-01 222]# touch lll.txt
[root@aming-01 ~]# ls /root/111/222/lll.txt
/root/111/222/lll.txt

- 这个时候还需要定义file list.txt

[root@aming-01 ~]# fg
vi /tmp/list.txt (wd: /usr/local/sbin)

/tmp/12.txt
/root/shell/1.sh
/root/111/222/lll.txt
~


:wq
[root@aming-01 ~]# cd /usr/local/sbin
[root@aming-01 sbin]# vi /tmp/list.txt
[root@aming-01 sbin]# cat /tmp/list.txt
/tmp/12.txt
/root/shell/1.sh
/root/111/222/lll.txt
[root@aming-01 sbin]#

- 再来编辑下rsync.expect

[root@aming-01 sbin]# vi 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:/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof

:wq

- rsync -avR --files-from=$file / root@$host:/ 内容里加了一个-R ,因为不能保证对方机器上有相同的路径,加上-R就会 自动创建没有的路径
- 1.同步的路径,需要保证对方机器也有这个相同的路径,如果没有路径,需要使用 -R 创建路径
- 咱们的list文件也有了,还需要一个ip.list,因为你的远程同步的机器不止一台,所以还要加上一个ip列表
- 2.因为实现分发系统,肯定是因为需要分发的机器数量过大,所以,定义好了 文件 的 list 列表文件以后, 还需要配置 ip 的列表文件

- 创建需要同步IP地址的列表文件

[root@aming-01 sbin]# vi /tmp/ip.txt

192.168.202.132
127.0.0.1



:wq

- 做这个expect脚本保证俩台机器的密码是一样的,如果不一样,就只能挨个去定义每台机器的密码

- 下面还需要创建一个rsync.sh
- 这个sh 的目的,就是遍历一下 ip列表文件中的 ip地址

[root@aming-01 sbin]# vi rsync.sh

#!/bin/bash
for ip in cat /tmp/ip.list
do
./rsync.expect $ip /tmp/file.list
done
~


:wq

-rsyncexpect加上执行权限,
-ip.txt 文件名改为ip.list
- 再来执行脚本rsync.sh 看下过程 sh -x

[root@aming-01 sbin]# vi rsync.sh
[root@aming-01 sbin]# chmod a+x rsync.expect

[root@aming-01 sbin]# mv /tmp/ip.txt /tmp/ip.list

[root@aming-01 sbin]# sh -x rsync.sh
++ cat /tmp/ip.list

  • for ip in 'cat /tmp/ip.list'
  • ./rsync.expect 192.168.202.132 /tmp/file.list
    spawn rsync -avR --files-from=/tmp/file.list / root@192.168.202.132:/
    root@192.168.202.132's password: 
    building file list ... rsync: link_stat "/root/shell/1.sh" failed: No such file or directory (2)
    done
    root/
    root/111/
    root/111/222/
    root/111/222/lll.txt
    tmp/

sent 173 bytes received 43 bytes 432.00 bytes/sec
total size is 5 speedup is 0.02
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1052) [sender=3.0.9]

  • for ip in 'cat /tmp/ip.list'
  • ./rsync.expect 127.0.0.1 /tmp/file.list
    spawn rsync -avR --files-from=/tmp/file.list / root@127.0.0.1:/
    The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
    ECDSA key fingerprint is 00:22:2a:58:d5:c3:79:dc:8b:d7:b1:91:5c:ec:27:83.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.
    root@127.0.0.1's password: [root@aming-01 sbin]#
  • 再去远程机器上aming-02 192.168.202.132 上面看下有没有那个ll1.txt文件
    [root@aming-02 ~]# ls -l /root/111/222/lll.txt
    -rw-r--r-- 1 root root 0 1129 22:40 /root/111/222/lll.txt
    [root@aming-02 ~]# 
  • 是由的,就是通过rsync -avR --files-from=list.txt / root@host:/ 来实现的文件,表示传输一个文件列表里的文件

  • 最重要的,expect脚本 必须加入执行权限
  • 文件不存在,会报错
  • 分发系统还有一个重要的关键是,确保同步的机器的密码一致,否则将不能实现同步;所以这就存在一个弊端,一旦脚本暴露,将会让别人知道如何登陆你机器;当然也有对应的解决办法,那就是使用密钥认证,这样的话,自然在命令行业省去“输入密码< password:" { send "$passwdr" } >''”和“定义密码< set passwd "123123a" >”的命令了

20.34 批量远程执行命令

  • 怎么去构建批量执行命令的脚本
    
    [root@aming-01 sbin]# vim 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"











:wq 
[root@aming-01 sbin]# chmod a+x exe.expect

- 还需要定义一个exe的 for 循环脚本

[root@aming-01 sbin]# vi exe.sh

#!bin/bash
for ip in cat /tmp/ip.list
do
./exe.expect $ip "hostname"
done


:wq

- 下面执行下脚本

[root@aming-01 sbin]# vi exe.sh
[root@aming-01 sbin]# sh exe.sh
spawn ssh root@192.168.202.132
root@192.168.202.132's password: 
Last failed login: Wed Nov 29 22:26:14 CST 2017 from 192.168.202.130 on ssh:notty
There were 2 failed login attempts since the last successful login.
Last login: Wed Nov 29 22:19:14 2017 from 192.168.202.130
[root@aming-02 ~]# hostname
aming-02
[root@aming-02 ~]# spawn ssh root@127.0.0.1
root@127.0.0.1's password: 
Last failed login: Wed Nov 29 22:58:00 CST 2017 from localhost on ssh:notty
There were 2 failed login attempts since the last successful login.
Last login: Wed Nov 29 19:52:21 2017 from 192.168.202.1
[root@aming-01 ~]# hostname
aming-01
[root@aming-01 ~]# [root@aming-01 sbin]#

- 可以看下文件内容

[root@aming-01 sbin]# cat 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"

[root@aming-01 sbin]#