expect解决shell脚本需交互问题

expect解决shell脚本需交互问题

Scroll Down

1、except作用

    except可以处理需要交互的命令,可以将交互过程写在shell脚本中无需用户与之交互,使之自动化完成。此外,用户可以控制在需要时直接交互,然后将控制权返回到脚本

2、例子

    对于第一次接触的童靴来说如果仅列举一些概念的话,很难理解其对应用法,这个我深有体会。所以先举些例子,下面接触到概念的时候结合例子理解!

   2.1 expect实现ssh非交互输入密码:

image.png

第1行的shebang就不再是常用的bash,这里要用except。系统一般不自带expect,需要使用的话需要自己安装# yum -y install expect

第5行的用于开启一个会话,这里就是执行ssh远程连接一台主机

第7行的expect{}表示从进程接收字符串,这里用于ssh的时候接收字符串,这不是随便填的,是根据进程真实出现的字符串进行填写( 如下图 )

image.png

第8行是当出现“yes/no”的时候,发送(相当于从键盘输入)yes和回车(\r),注意这里加上分号“;”是因为将匹配的字符串和send都写在了一行,exp_continue表示当expect{}中包含多行匹配的时候非最后一个匹配都要加上,表示执行或不执行发送动作都要继续进行匹配

第9行表示匹配到password字符串时,发送(相当于从键盘输入)password值和回车,此处也就是输入对方主机的root密码。如下图

image.png

第12行的interact表示expect命令完成后保持交互状态,也就是停留在对方的shell

    执行之后如下:

image.png

    上述简单脚本也可以写成不带“;”分号的!

   2.2 shell脚本嵌套使用expect

image.png

   2.3 expect使用位置参数

   expect的位置参数不是$1,$2,而是 “lindex $argv 0" "lindex $argv 1"等等

image.png

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到时,主线程才退出**