shell嵌套expect脚本实现远程打包及本地安装
概述
通过shell嵌套expect脚本实现远程打包rpm安装包并更新本地安装包。
expect相关知识
Expect是一个可以和交互式程序对话的程序,Expect可以做的事情:telnet、ftp、ssh和scp等等。
常用命令
spawn
spawn [args] program [args]
创建一个新的进程运行program [args]。program的标准输入、标准输出和标准错误都连接到Expect,这样程序就可以被Expect读写了。当Expect执行close命令或者进程关闭了任何文件标识符时,连接会断开。
当以spawn启动一个进程时,进程描述符被赋给变量spawn_id,它表示了当前进程,spawn_id可被读写,以实现任务控制。
expect
expect [[-opts] pat1 body1] … [-opts] patn [bodyn]
等待,直到模式patn匹配到spawn打开的进程的输出,超过指定的时间,或遇到EOF。
如果模式关键字是eof,那么对应的执行体是处理遇到文件结尾的
如果模式关键字是timeout,那么对应的执行体是处理超时的,如果没有指明timeout,则默认不会做任何动作。默认的超时时间是10秒,但是可以通过如下命令重设
set timeout 30
如果设置为-1,则意味着无限等待。
如果模式关键字是default,那么对应的执行体会处理超时或文件结尾。
每次新的输出到达时,会按顺序比较每个模式,如果模式匹配到了,那么对应的执行体会被执行。如果有多个模式匹配,只执行第一个出现的。
下面的例子,看起来像一个可以成功登陆的脚本片段。
expect {
“yes/no” {send “yes\r”;exp_continue}
“password:” {send “$passwd\r”}
default {exit}
}
exp_continue
exp_continue [-continue_timer]
允许expect继续执行自身而不是往下执行,默认情况下,exp_continue会重置timeout,如果不想重置timeout,使用-continue_timer选项。
expect_user
expect_user [expect_args]
类似expect,不过是从标准输入读取字符,行必须以回车结尾,以使expect能识别它们。
send
send [-flags] string
发送string到当前进程,例如:
send “hello world\r”
就是发送“hello world“到当前进程,
字符会立即被发送,尽管那些行缓冲的程序只会在有回车键时才读取,回车键用’\r’表示。因此,下面的示例和上面示例等同。
send "hello "
send “world\r”
send_error
send_error [-flags] string
类似send,不过输出发送到标准错误,而不是当前进程
send_log
send_log [–] string
类似send,不过string只发送到log文件。(see log_file)
send_tty
send_tty [-flags] string
类似send,不过输出发送到/dev/tty而不是当前进程。
send_user
send_user [-flags] string
类似send,不过输出发送到标准输出,而不是当前进程。
interact
interact [string1 body1] … [stringn [bodyn]]
将当前进程的控制权交付给用户。
string-body对可以作为参数,以使当有string输入时,执行body。下面的示例看上去是一个可运行片段。
interact {
“abc” {send_user “you typed abc\n”}
“123” {send_user “you typed 123\n”}
}
输入的字符会按string列出的顺序进行匹配,当有部分匹配时,当前输入的字符不会被发送到当前进程,只有当后续输入的字符不能使之匹配时才会发送,若匹配则执行body。以上例为例,在输入"abc"的过程中,进程不会回显这些字符,如果输入"abq",则只有在输入到"q"时,"abq"才会同时被回显。
当模式是eof时,表示遇到文件结尾的行为,默认是"return"。
当模式是timeout时(需指定超时时间),表示在指定时间没有输入时的行为,此项没有默认的超时时间,变量timeout的值在此无效。
当模式是null时,仅当匹配到一个单个ascii字符"0"时才会执行后面的执行体。没有可用的办法来匹配0字节数据,不论是通过全匹配和正则匹配。
interact中的return使interact返回到它的调用。而inter_return使interact的调用执行return。
sleep
sleep seconds
脚本进入睡眠模式,睡眠时间单位为秒
close
close [-slave] [-onexec 0|1] [-i spawn_id]
关闭连接到当前进程的连接
exit
Expec
退出
expect安装
[root@wz ~]# yum install install tcl tk expect
代码实现
#!/bin/bash
# you must install tcl tk expect
# Usage:sh install.sh
# This script will make a rpm package at 192.168.0.26 and scp this package from
# 26 to the machine that you execute it, and uninstall old package, install
# new package at your machine, and start it.
# the package at here
RPM_PATH="/opt/software/"
# the package will be installed here
INSTALL_PATH="/apps/"
# app1 is installed here, APP1_TOP is need by rpm package.
APP1_TOP="/usr/share/app1"
# make rpm package here
_ip="192.168.0.26"
# ssh user
_user="root"
# ssh password
_pass="root"
# is close function about remote desktop
_close="y"
# make-core-rpm.sh is here
_shell_path="/home/wangzheng/12_28/app2/rpm-packaging/"
# rpm package name
_pak_name="app2.rpm"
# echo message
function echoEvent {
[[ "$1" == "0" ]] && echo "$2"
}
# ssh and make rpm package
function makeRpm {
/usr/bin/expect <<EOF
set timeout 600
spawn ssh $_user@$_ip
expect {
"*password:"
{send "$_pass\r"}
}
expect "*#"
send "cd $_shell_path;source /root/env.sh;sh make-core-rpm.sh\r"
expect "Do you want to close TeamWork Service ?"
send "$_close\r"
expect "+ rm -rf /tmp/rpm-app2-core*"
send "exit\r"
expect eof
EOF
}
# scp rpm package from 26
function scpPak {
echo "scp rpm from 26..."
/usr/bin/expect <<EOF
set timeout 30
spawn scp $_user@$_ip:$_shell_path/$_pak_name $RPM_PATH
expect {
"yes/no" {send "yes\r"; exp_continue}
"*password" {send "$_pass\r"; exp_continue}
}
EOF
echoEvent $? "scp rpm package done"
}
# uninstall old rpm package
function unInstall {
echo "uninstalling old app2..."
rpm -qa | grep app2 | xargs rpm -e &> /dev/null
echoEvent $? "uninstall old app2 done"
}
# install new rpm package and initial sql file
function installPkg {
echo "installing app2 to ${INSTALL_PATH}..."
rpm -ivh ${RPM_PATH}/app2.rpm --prefix=${INSTALL_PATH}
echoEvent $? "install app2 done"
echo "initialing sql file..."
mysql<${INSTALL_PATH}/database/MYSQL/initial_deploy.sql
echoEvent $? "initial sql file done"
}
# start app2
function startApp2 {
echo "starting app2..."
. ${INSTALL_PATH}/profile.app2
app2 start all
echoEvent $? "start app2 done"
}
#========================================Main====================================
export APP1_TOP
makeRpm
scpPak
unInstall
installPkg
startChesspro