24 Dec 2014
前提:知道目标机器的帐号密码;
操作:自动登录(可用密钥取代此过程)、远程执行命令、远程同步文件
expect命令安装:yum install -y expect
ssh命令安装:yum install -y openssh-clients
仅有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.
自动登录脚本内容(登录完毕后等待交互)
#!/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)
一个快速、多功能、远程(含本地)的文件拷贝工具
man page description
a fast, versatile, remote (and local) file-copying tool
rsync [参数] 源文件(可远程) 目标文件(可远程)
man page description
Pull:rsync [OPTION…] [USER@]HOST:SRC… [DEST]
Push:rsync [OPTION…] SRC… [USER@]HOST:DEST
源文件及目标文件所在机器必须同时安装了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
对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台。所以,自动同步文件是至关重要的。
首先要有一台模板机器,把要分发的文件准备好,然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可。
rsync -av –files-from=list.txt / root@host:/
从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
执行过程 “` bash [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]#”`