1、except作用
except可以处理需要交互的命令,可以将交互过程写在shell脚本中无需用户与之交互,使之自动化完成。此外,用户可以控制在需要时直接交互,然后将控制权返回到脚本
2、例子
对于第一次接触的童靴来说如果仅列举一些概念的话,很难理解其对应用法,这个我深有体会。所以先举些例子,下面接触到概念的时候结合例子理解!
2.1 expect实现ssh非交互输入密码:
第1行的shebang就不再是常用的bash,这里要用except。系统一般不自带expect,需要使用的话需要自己安装# yum -y install expect
第5行的spawn用于开启一个会话,这里就是执行ssh远程连接一台主机
第7行的expect{}表示从进程接收字符串,这里用于ssh的时候接收字符串,这不是随便填的,是根据进程真实出现的字符串进行填写( 如下图 )
第8行是当出现“yes/no”的时候,发送(相当于从键盘输入)yes和回车(\r),注意这里加上分号“;”是因为将匹配的字符串和send都写在了一行,exp_continue用处是当expect{}中包含多行匹配的时候非最后一个匹配都要加上,表示执行或不执行发送动作都要继续进行匹配
第9行表示匹配到password字符串时,发送(相当于从键盘输入)password值和回车,此处也就是输入对方主机的root密码。如下图
第12行的interact表示expect命令完成后保持交互状态,也就是停留在对方的shell
执行之后如下:
2.2 shell脚本嵌套使用expect
# 此处 “ -EOF ” 的 “ - ” 是允许expect部分的语句允许缩进,可以不顶格书写 /usr/bin/expect <<-EOF
2.3 expect使用位置参数
expect的位置参数不是$1,$2,而是 “lindex $argv 0" "lindex $argv 1"等等
3、expect语法
expect [ 选项 ] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
选项:
-c:从命令行执行expect脚本,默认expect是交互地执行的
-d:允许输出调试性信息
- D:开启交互调试器。后面必须跟有一个整数值作为参数,当值为非零或是按下CTRL+C的时候(或是遇到断点,或是在脚本中恰好出现其他的调试语句),调试器会在进行下一次Tcl Procedure前取得控制权
- f :指明从哪个文件中读取命令。这个选项是可选的,因为只有当使用”#!”时它才有可能被用到。而其他选项可以写在命令行中
-b:默认情况下,命令文件是全部读入内存一并执行的。但有些时候需要每次只读一行。例如:stdin(标准输入)就是这样读取的。如果强制任意文件以这种方式(每次读一行)执行的话就使用”-b”选项
-i :使Expect能交互式的提示输入命令,而不是从文件中读取。在遇到文件尾或是执行了exit命令时,提示输入命令终止
-v :用来打印出版本号,然后退出
4、关键字
spawn: 表示开启一个会话
只有spawn执行的命令结果才会被expect捕捉到,因为spawn会启动一个进程,只有这个进程的相关信息才会被捕捉到,主要包括:标准输入的提示信息,eof和timeout
send: 用于向进程发送字符串
expect{ }: 表示期望的事情,当出现期望的字样时做什么事情( 也就是从进程接收字符串 )
exp_continue: 表示当expect{ }中有多行带匹配字符串时,执行或不执行发送动作都要继续匹配
expect eof:表示捕获到spawn命令启动的进程的结束状态
expect 会启动一个主线程,spawn以及send等命令都会启动各自的子线程,如果没有 expect eof的话,主线程不会等待所有的子线程结束才退出,而是直接退出,导致所有的子线程释放( 也就是说send可能不会被执行 )。
解决方法可以有两个:
第一个,让主线程sleep一段时间(
set timeout XX
),等待所有的子线程处理完;第二个,expect eof阻塞主线程,等待所有的子线程处理完之后,或者timeout
时间结束,主线程才退出interact:执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上
5、执行完expect的一些小问题
使用expext处理ssh交互问题,脚本执行完expect之后一段时间才继续往下走原因:
expect 会启动一个主线程,spawn以及send等命令都会启动各自的子线程,如果没有 expect eof的话,主线程不会等待所有的子线程结束才退出,而是直接退出,导致所有的子线程释放( 也就是说send可能不会被执行)。解决方法可以有两个:第一个,让主线程sleep一段时间(
set timeout XX
),等待所有的子线程处理完;第二个,expect eof阻塞主线程,等待所有的子线程处理完之后,或者timeout到时,主线程才退出**