Here Documents 结合expect的使用--(2)
我们已经知道expect可以帮我们自动完成“交互工作”,但是如果我们需要拿到 通过expect spawn的sub-process 所执行命令的结果,那么怎么做呢?
通过重定向当然是不可能的了,因为spawn产生的是一个由expect来维护的一个子进程,当这个sub-process结束的时候,已经没有办法再进入了,就算重定向成功,也是无法拿到结果,况且重定向是否成功,我们也是没有办法知道的;
expect给我们提供了一个特定的访问方法,那就是用 expect_out, 常用的有$expect_out(buffer) 或者 $expect_out(NUMBER, string) , 把 $expect_out(buffer) 或者 $expect_out(NUMBER, string) 的结果通过set 赋值给变量,然后把变量写入文件就可以拿到命令的执行结果了;
要使用expect_out, 我们必须首先理解expect_out. 这里介绍expect_out到底保存了什么?
当expect执行匹配验证的时候,它是 把sub-process的输出作为 被查找的对象,而用户提供的“匹配关键字或者正则表达式” 作为“查找对象”,那么被查找对象总是sub-process从头开始的所有输出吗? 当然不是,”被查找对象“总是从前一次匹配的位置开始(不含已经匹配的内容),一直到sub-process的最新输出;每一次expect的匹配都是如此执行的,这时候如果匹配到了,那么就会把上一次匹配位置开始 到当前匹配的结果保存下来,这个结果可以通过 $expect_out(buffer) 来访问到. 如果没有匹配到,那么通过$expect_out(buffer)访问到的结果是上一次expect之后的结果;
这一段理解起来有一点拗口,不过对使用 expect_out非常重要,我们通过下面的例子进行验证:
[root@instance-6p8qz002 ~]# cat t.sh
#!/bin/bash
for i in `cat t.txt`;do
ofile=$i #用于设置文件名称;
expect <<-EOF
log_file ./exp_log #开启expect的log, 只需要指定 log_file 变量就可以了,很方便是不是?
set output [open $ofile w] #以w的方式打开文件
spawn ssh test_user@$I
expect "assword" #第一次进行expect, 匹配到就输入密码;
send "$1\r" #输入密码;
expect "~]" #第二次进行expect匹配
send "\r"
set outcome \$expect_out(buffer) #此时获取$expect_out(buffer)的值,就是前面第一次匹配到第二次匹配之间的内容;我们写入到文件中,随后进行验证;
puts \$output \$outcome #把内容写入文件
expect eof
exit
EOF
done
#执行上面脚本,这里忽略执行过程;
#查看执行结果:localhost 文件的内容是通过 脚本把$expect_out(buffer)的内容保存下来的结果,而exp_log文件的内容是expect的日志文件,日志文件里面记录了sub-process的所有输出;
[root@instance-6p8qz002 ~]# cat localhost
:
Last login: Fri Oct 11 20:42:19 2019 from ::1
[test_user@instance-6p8qz002 ~]
#查看expect的log文件;
[root@instance-6p8qz002 ~]# cat -n exp_log
1 spawn ssh test_user@localhost
2 test_user@localhost's password:
3 Last login: Fri Oct 11 20:42:19 2019 from ::1
4 [test_user@instance-6p8qz002 ~]$
5 [test_user@instance-6p8qz002 ~]$
[root@instance-6p8qz002 ~]#
从上面的expect的log文件exp_log中可以看到:
第一次调用expect匹配到第2行的assword,这一行后面还有一个冒号;
第二次调用expect,是从第二行的冒号开始进行匹配的,一直到第4行,发现了匹配的字符串:~];
根据前面的解释,从第一次匹配后的冒号到 第二次匹配的字符串"~]"之间的内容,就应该是$expect_out(buffer) 的内容,这是根据exp_log ,通过manually分析出来的内容;
而在脚本中已经把 $expect_out(buffer)的结果存到文件localhost中了;手动分析的结果和脚本执行的结果一致,所以上述的解释是合理的;
下面修改脚本的内容,使第二次的匹配失败,看看$expect_out(buffer)的结果:
#把上面脚本的第10行的内容修改为:expect "#]" 就可以了;
#运行脚本,并查看结果
[root@instance-6p8qz002 ~]# cat localhost
test_user@localhost's password
[root@instance-6p8qz002 ~]# cat -n exp_log
1 spawn ssh test_user@localhost
2 test_user@localhost's password:
3 Last login: Fri Oct 11 20:49:06 2019 from ::1
4 [test_user@instance-6p8qz002 ~]$
5 [test_user@instance-6p8qz002 ~]$
因为第二次expect执行expect "#]" 进行匹配,结果当然是匹配不上,所以$expect_out(buffer) 的结果并没有更新,还是从spawn 开始到第一次匹配之间的内容,所以localhost的结果只有一条内容.
本文原创,转载请注明出处