linux's docs

16.1.0: 文件分发-expect+rsync


1. expect基础

1) 学习目的

前提:知道目标机器的帐号密码;
操作:自动登录(可用密钥取代此过程)、远程执行命令、远程同步文件

2) 基础命令安装

expect命令安装:yum install -y expect
ssh命令安装:yum install -y openssh-clients

3) 扩展命令或选项作用解释

仅有spawn是命令

timeout
我们可以通过设置给timeout一个值(代表秒数)或者一个动作(可以不给出)来使得expect命令未寻找到关键字段情况发生时,告诉脚本如何处理此情况。

man page description
The pattern timeout introduces a timeout (in seconds) and action that is executed after no characters have been read for a given time. The timeout pattern applies to the most recently specified process. There is no default timeout. The special variable "timeout" (used by the expect command) has no affect on this timeout.

spawn
给进程一个spawn id,就像开了一个专属的tty给spawn用于执行该进程。

man page description
returns the UNIX process id. If no process is spawned, 0 is returned. Internally, spawn uses a pty, initialized the same way as the user's tty.

exp_continue [-continue_timer]
此命令允许expect自己循环执行,而并不是按照默认的模式执行。默认情况下exp_continue会重置timeout的定时器,但是如果我们同时使用了-continue_timer的话,exp_continue就不会重置timeout定时器了。

man page description
The command exp_continue allows expect itself to continue executing rather than returning as it normally would. By default exp_continue resets the timeout timer. The -continue_timer flag prevents timer from being restarted. (Seeexpect for more information.)

interact [string1 body1] ... [stringn [bodyn]]
此命令将当前进程的控制权交给用户,允许用户键盘敲出的字符传送给当前进程,而进程产生的错误输出和标准输出会传递到当前屏幕

man page description
gives control of the current process to the user, so that keystrokes are sent to the current process, and the stdout and stderr of the current process are returned.

EOF
有时候我们会用expect侦测这个返回值,此返回值代表的含义是当前进程已经执行到end-of-file。(就像timeout到时间了以后会返回timeout,eof就是一个进程执行状态返回值)

man page description
The pattern eof introduces an action that is executed upon end-of-file. A separate eof pattern may also follow the -outputflag in which case it is matched if an eof is detected while writing output. The default eof action is "return", so that interactsimply returns upon any EOF.

4) 实例演示

自动登录脚本内容(登录完毕后等待交互)

#!/usr/bin/expect
# Program
#       used for auto login
# Author : Zhao Peiwu
# Date : 25/12/2014

set user [lindex $argv 0]
# [lindex $argv 0]相当于shell中的$1
set host [lindex $argv 1]
# 把第二个参数赋值给host,即ip地址
set passwd "your passwd"
spawn ssh $user@$host
expect {
"yes/no" {send "yes"}
# expect查询到"yes/no"字符串,然后发送"yes"

"password:" {send "$passwd\r"}
# 发送passwd变量的值和\r(回车键,但不换行)
}
interact
# 登录成功后保持交互状态

执行结果

# 传递参数"root"和IP进入expect脚本
[root@web01 expect]# expect login.exp root 192.168.0.30    
spawn ssh root@192.168.0.30
root@192.168.0.30\'s password:
Last login: Thu Dec 25 11:36:09 2014 from web01.gateway.2wire.net
# 正常登入

自动登录脚本内容(登陆后,执行命令然后退出)

#!/usr/bin/expect
# Program
#       used for auto login
# Author : Zhao Peiwu
# Date : 25/12/2014

set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "sudoroot88"
#set timeout 10
spawn ssh $user@$host
expect {
"yes/no" {send "yes"}
"password:" {send "$passwd\r"}
# 要把exp_continue去掉,否则退出会有延迟
}
expect "]*"
# 执行命令靠这个匹配到待输入命令状态,然后后面可以send命令字符串
send "exit\r"
# 传送"exit\r"到进程

执行结果

[root@web01 expect]# expect login.exp root 192.168.0.30
spawn ssh root@192.168.0.30
root@192.168.0.30\'s password:
Last login: Thu Dec 25 13:45:29 2014 from web01.gateway.2wire.net
[root@web02 ~]# [root@web01 expect]#
# 立刻退出

exp_continue的效果(为了看到效果,特意把密码弄成错误的) 脚本内容

#!/usr/bin/expect
# Program
#       used for auto login
# Author : Zhao Peiwu
# Date : 25/12/2014

set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "wrong passwd"
set timeout 10
spawn ssh $user@$host
expect {
"yes/no" {send "yes"}
"password:" {send "$passwd\r";exp_continue}
# timeout到期了以后expect会重新传递passwd的值
}
interact

执行结果

[root@web01 expect]# expect login.exp root 192.168.0.30
spawn ssh root@192.168.0.30
root@192.168.0.30\'s password:
Permission denied, please try again.
# 因为是错误密码,所以登录失败,然后timeout到期后本应该退出,但因为有exp_continue的存在,所以继续循环执行
root@192.168.0.30\'s password:             
Permission denied, please try again.
root@192.168.0.30\'s password:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
spawn_id: spawn id exp4 not open
    'while executing'
"interact"
    (file "login.exp" line 16)

2. rsync

1) 作用:

一个快速、多功能、远程(含本地)的文件拷贝工具

man page description
a fast, versatile, remote (and local) file-copying tool

2) 语法:

rsync [参数] 源文件(可远程) 目标文件(可远程)

man page description
Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST:DEST

3) 参数:

  • "-a" 存档模式,相当于-rlptgoD所有参数的集合

    man page description
    --archive archive mode; equals -rlptgoD (no -H,-A,-X)

  • "-v" 增量拷贝

    man page description
    --verbose increase verbosity
    "--files-from" 指定filelist

4) 实例演示:

源文件及目标文件所在机器必须同时安装了rsync命令才可执行

[root@web01 expect]# rsync -av /root/shell root@192.168.0.30:/tmp
root@192.168.0.30\'s password:
bash: rsync: command not found
# 为啥会报错? 因为我在目标机器上把rsync命令卸载掉了
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]


# 赶快把目标机器上的rsync命令安装上(yum install -y rsync)
[root@web01 expect]# rsync -av /root/shell root@192.168.0.30:/tmp
root@192.168.0.30\'s password:
sending incremental file list
shell/
shell/expect/
shell/expect/login.exp

sent 408 bytes  received 39 bytes  99.33 bytes/sec
total size is 280  speedup is 0.63

用脚本来自动同步文件
脚本内容

#!/usr/bin/expect
# Program
# rsync auto archive file to the other machine
# Author : Zhao Peiwu
# Date : 25/12/2014

set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "your password"
spawn rsync -av /root/shell $user@$host:/root/shell
expect {
"yes/no" {send "yes\r"}
"password" {send "$passwd\r"}
}
expect eof

执行过程

# web02上没有/root/shell的情况
[root@web02 expect]# ls -d /root/shell
ls: cannot access /root/shell: No such file or directory

# web01上再次运行
[root@web01 expect]# expect rsync.expect root 192.168.0.30
spawn rsync -av /root/shell root@192.168.0.30:/root/shell
root@192.168.0.30\'s password:
sending incremental file list
created directory /root/shell
# 不存在的shell文件夹被创建了,可是只能创建一层目录
shell/
shell/expect/
shell/expect/login.exp
shell/expect/rsync.expect

sent 799 bytes  received 58 bytes  1714.00 bytes/sec
total size is 602  speedup is 0.70

3. 构建文件分发系统

1) 需求背景

对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台。所以,自动同步文件是至关重要的。

2) 实现思路

首先要有一台模板机器,把要分发的文件准备好,然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可。

3) 核心命令

rsync -av --files-from=list.txt / root@host:/

4) 文件分发系统的实现

从filelist中获取文件路径,然后通过rsync同步

脚本内容

#!/usr/bin/expect
# Program
# rsync auto archive file to the other machine
# Author : Zhao Peiwu
# Date : 25/12/2014

set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "your password"
set file [lindex $argv 2]
spawn rsync -av --files-from=$file / $user@$host:/
expect {
"yes/no" {send "yes\r"}
"password" {send "$passwd\r"}
}
expect eof

执行过程

[root@web01 expect]# cat rsynclist
/root/good
[root@web01 expect]# expect /root/shell/expect/autors.expect root 192.168.0.30 rsynclist
spawn rsync -av --files-from=rsynclist / root@192.168.0.30:/
root@192.168.0.30\'s password:
building file list ... done
root/
root/good

sent 107 bytes  received 40 bytes  294.00 bytes/sec
total size is 12  speedup is 0.08

expect脚本:autoip.exp
可以通过在expect脚本内部设置命令变量cm
通过shell脚本的for循环命令来调用iplist里面的ip来逐个执行cm变量的命令

#!/usr/bin/expect
# Program
#       used for auto login
# Author : Zhao Peiwu
# Date : 25/12/2014

set user [lindex $argv 0]
set host [lindex $argv 1]
set cmd [lindex $argv 2]    #第三个参数用来传递命令
set passwd "your passwd"
#set timeout 10
spawn ssh $user@$host
expect {
"yes/no" {send "yes"}
"password:" {send "$passwd\r"}
}
expect "]*"
send "$cmd\r"     #登陆后执行命令
expect "]*"
send "exit\r"

shell脚本:autoip.sh

#!/bin/bash
path1="/root/shell/expect"     
## 把autoip.exp路径指定一下

for ip in `cat $path1/iplist`
## ip变量是在iplist中的ip列表,当然我只有两台机器,所以iplist只有一个ip

do
        echo $ip
        /usr/bin/expect $path1/autoip.exp root $ip "w;pwd;ls ."
done

执行过程

[root@web01 shell]# sh autoip.sh
192.168.0.30
spawn ssh root@192.168.0.30
root@192.168.0.30\'s password:
Last login: Thu Dec 25 17:15:23 2014 from web01.gateway.2wire.net
w;pwd;ls .              
# 登录上机器以后执行三条命令,用分号间隔
 17:22:44 up 18:08,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    web01.gateway.2w 17:22    0.00s  0.03s  0.00s w
/root
12.log  1.txt  awk  for.sh  good    perm       shell     stdin   woqunimei
1.log   aa     dd   fugai   md.txt  regep.txt  sort.txt  stdout
[root@web02 ~]# [root@web01 shell]#

Contents