利用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
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。