利用expect命令实现Shell自动化交互的方法详解
背景
linux脚本中有很多场景是进行远程操作的,例如远程登录ssh、远程复制scp、文件传输sftp等。这些命令中都会涉及到安全密码的输入,正常使用命令时是需要人工手动输入密码并接受安全验证的。为了实现自动化远程操作,我们可以借用expect的功能。
expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。expect是不断发展的,随着时间的流逝,其功能越来越强大,已经成为系统管理员的的一个强大助手。expect需要Tcl编程语言的支持,要在系统上运行expect必须首先安装Tcl。
expect的安装
expect是在Tcl基础上创建起来的,所以在安装expect前我们应该先安装Tcl。
(一)Tcl安装
主页:http://www.tcl.tk
下载地址:http://www.tcl.tk/software/tcltk/downloadnow84.tml
1.下载源码包
wgethttp://nchc.dl.sourceforge.net/sourceforge/tcl/tcl8.4.11-src.tar.gz
2.解压缩源码包
tarxfvztcl8.4.11-src.tar.gz
3.安装配置
cdtcl8.4.11/unix ./configure--prefix=/usr/tcl--enable-shared make makeinstall
注意:
1、安装完毕以后,进入tcl源代码的根目录,把子目录unix下面的tclUnixPort.hcopy到子目录generic中。
2、暂时不要删除tcl源代码,因为expect的安装过程还需要用。
(二)expect安装(需Tcl的库)
主页:http://expect.nist.gov/
1.下载源码包
wgethttp://sourceforge.net/projects/expect/files/Expect/5.45/expect5.45.tar.gz/download
2.解压缩源码包
tarxzvfexpect5.45.tar.gz
3.安装配置
cdexpect5.45 ./configure--prefix=/usr/expect--with-tcl=/usr/tcl/lib--with-tclinclude=../tcl8.4.11/generic make makeinstall ln-s/usr/tcl/bin/expect/usr/expect/bin/expect
expect
expect的核心是spawn、expect、send、set。
spawn调用要执行的命令
- expect等待命令提示信息的出现,也就是捕捉用户输入的提示:
- send发送需要交互的值,替代了用户手动输入内容
- set设置变量值
- interact执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。
- expecteof这个一定要加,与spawn对应表示捕获终端输出信息终止,类似于if....endif
expect脚本必须以interact或expecteof结束,执行自动化任务通常expecteof就够了。
其他设置
- 设置expect永不超时settimeout-1
- 设置expect300秒超时,如果超过300没有expect内容出现,则退出settimeout300
expect编写语法
expect使用的是tcl语法
- 一条Tcl命令由空格分割的单词组成.其中,第一个单词是命令名称,其余的是命令参数
cmdargargarg - $符号代表变量的值.在本例中,变量名称是foo.
$foo - 方括号执行了一个嵌套命令.例如,如果你想传递一个命令的结果作为另外一个命令的参数,那么你使用这个符号
[cmdarg] - 双引号把词组标记为命令的一个参数."$"符号和方括号在双引号内仍被解释
"somestuff" - 大括号也把词组标记为命令的一个参数.但是,其他符号在大括号内不被解释
{somestuff} - 反斜线符号是用来引用特殊符号.例如:n代表换行.反斜线符号也被用来关闭"$"符号,引号,方括号和大括号的特殊含义
示例
login.exp专用于远程登录,快捷使用方式:login.exp"exclude""${remote_ip}""${remote_user}""${remote_passwd}""${remote_command}"
#!/usr/bin/expect-f
##########################################################
#通过SSH登陆和执行命令
#参数:1.Use_Type[check/execute]
#2.SSHServerIp
#3.SSHUser
#4.SSHPassword
#5.CommandList[多个命令间以;间隔]
#返回值:
#0成功
#1参数个数不正确
#2SSH服务器服务没有打开
#3SSH用户密码不正确
#4连接SSH服务器超时
##########################################################
procusage{}{
regsub".*/"$::argv0""name
send_user"Usage:\n"
send_user"$nameUse_TypeSSHServerIpSSHUserSSHPasswordCommandList\n"
exit1
}
##判断参数个数
if{[llength$argv]!=5}{
usage
}
#设置变量值
setUse_Type[lindex$argv0]
setSSHServerIp[lindex$argv1]
setSSHUser[lindex$argv2]
setSSHPassword[lindex$argv3]
setCommandList[lindex$argv4]
#spawnping${SSHServerIp}-w5
#expect{
#-nocase-re"100%packetloss"{
#send_error"Ping${SSHServerIp}isunreachable,PleasechecktheIPaddress.\n"
#exit1
#}
#}
settimeout360
setresssh0
#定义变量标记ssh连接时是否输入yes确认
setinputYes0
setok_stringLOGIN_SUCCESS
if{$Use_Type=="check"}{
#激活ssh连接,如果要需要输入yes确认,输入yes,设置inputYes为1,否则输入ssh密码
spawnssh${SSHUser}@${SSHServerIp}"echo$ok_string"
}else{
spawnssh${SSHUser}@${SSHServerIp}"$CommandList"
}
expect{
-nocase-re"yes/no"{
send--"yes\n"
setinputYes1
}
-nocase-re"assword:"{
send--"${SSHPassword}\n"
setresssh1
}
#-nocase-re"Lastlogin:"{
#send--"${CommandList}\n"
#}
$ok_string{}
-nocase-re"Connectionrefused"{
send_error"SSHservicesat${SSHServerIp}isnotactive.\n"
exit2
}
timeout{
send_error"ConnecttoSSHserver${SSHUser}@${SSHServerIp}timeout(10s).\n"
exit4
}
}
#如果输入了yes确认,输入ssh密码
if{$inputYes==1}{
expect{
-nocase-re"assword:"{
send--"${SSHPassword}\n"
setresssh1
}
}
}
#如果出现tryagain或者password:提示,说明输入的用户密码错误,直接退出。
if{$resssh==1}{
expect{
-nocase-re"tryagain"{
send_error"SSHuser:${SSHUser}passwderror.\n"
exit3
}
-nocase-re"assword:"{
send_error"SSHuser:${SSHUser}passwderror.\n"
exit3
}
eof{}
}
}
send_error--"$expect_out(buffer)"
#-nocase-re"Nosuchuser"{
#send_error"Nosuchuser.\n"
#exit5
#}
#exit
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。