在上一节中,我们学习了 expect_out,但是还没有演示到底如何使用expect_out来获得spawn出来的sub-process中执行的命令的结果,这里我们来演示如下:
#我们这里来获取top命令的前10行结果,脚本内容如下:
[root@instance-6p8qz002 ~]# cat m.sh
#!/bin/sh
echo "" >./exp_log
for i in `cat t.txt`;do
ofile=$i
expect <<-EOF
log_file ./exp_log
set output [open $ofile w]
spawn ssh test_user@$i
expect "assword"
send "$1\r"
expect "~]"
send "top -bn 1 | head \r"
send "\r" #如果没有这一行,那么获取到的结果只有9行,而不是10行
#如果不想用 send "\r"这一行,还想获得10行的输出怎么办?这时候,我们可以通过修改expect的表达式为: expect -re "~]" 来实现
expect -re "(.*)\r\n(.*)\r\n(.*)~]"
set outcome \$expect_out(1,string)
puts \$output \$outcome
send "exit\r"
expect eof
exit
EOF
done
[root@instance-6p8qz002 ~]#
#top -bn1 |head 的结果保存在文件localhost中,查看localhost的结果:
[root@instance-6p8qz002 ~]# cat localhost
$ top -bn 1 | head
top - 12:11:54 up 7 days, 23:50, 8 users, load average: 0.00, 0.01, 0.05
Tasks: 109 total, 2 running, 107 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1014876 total, 81292 free, 190392 used, 743192 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 591152 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 125476 3584 2236 S 0.0 0.4 0:08.30 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:54.61 ksoftirqd/0
在上面的脚本中, send "\r" 这一句非常重要,否则得到的结果只有9行,而不是10行,原因是什么呢?
如果没有send "\r" 这一行,我们可以看到exp_log的内容如下:
1
2 spawn ssh test_user@localhost^M
3 test_user@localhost's password: ^M
4 Last login: Sun Oct 13 12:11:54 2019 from ::1^M^M
5 ^[[?1034h[test_user@instance-6p8qz002 ~]$ top -bn 1 | head ^M
6 top - 12:21:44 up 8 days, 0 min, 9 users, load average: 0.00, 0.01, 0.05^M
7 Tasks: 111 total, 1 running, 110 sleeping, 0 stopped, 0 zombie^M
8 %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni, 93.3 id, 6.7 wa, 0.0 hi, 0.0 si, 0.0 st^M
9 KiB Mem : 1014876 total, 77276 free, 193380 used, 744220 buff/cache^M
10 KiB Swap: 0 total, 0 free, 0 used. 587960 avail Mem ^M
11 ^M
12 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND^M
13 1 root 20 0 125476 3584 2236 S 0.0 0.4 0:08.31 systemd^M
14 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd^M
15 3 root 20 0 0 0 0 S 0.0 0.0 0:54.67 ksoftirqd/0^M
16 [test_user@instance-6p8qz002 ~]$ exit^M
17 logout^M
18 Connection to localhost closed.^M^M
在脚本中的正则表达式为: (.*)\r\n(.*)\r\n(.*)~], 其匹配的内容分析如下:
1). 表达式的最后为 ~], 最大只能匹配到 16行的 ~]
2). 表达式匹配的开始位置为:第5行的$符号处
3). 在上述的5到16行之间,需要两个 换行符好进行分割,而实际上我们可以看到每一行都有一个换行符号,但是根据从前向后,每个(.*)都是尽可能的最大程度去匹配的原则,所以,第一个 (.*)匹配的就是 第5行的$到14行的末尾,而第二个(.*)匹配的就是15行,最后一个(.*)匹配的就是16行的开始到字符串“8qz002"
到这里,相信你已经get到了吧!!!是不是so easy ?
如果我们修改上述脚本,尝试发送的命令是: top -bn2 , 而不是top -bn1|head, 我们是否还可以获得期望的输出呢? 答案是否定的,因为 expect_out 并不是无限大的,当expect_out满了以后,就会丢弃匹配结果中前面的部分;那非要获得输出结果的全部应该怎么办呢?
当expect_out满的时候,会触发 full_buffer 的匹配,我们只需要对这个full_buffer的匹配进行处理,把expect_out的内容取出,然后再继续进行expect就可以了(通过exp_continue),代码如下:
#!/bin/bash
echo "" >./exp_log
for i in `cat t.txt`;do
ofile=$i
expect <<-EOF
set outcome "" #设置自定义的变量outcome.
log_file ./exp_log
set output [open $ofile w]
spawn ssh test_user@$i
expect "assword"
send "$1\r"
expect "~]"
send "top -bn2\r"
expect { #在此expect中可能触发 full_buffer,所以修改该段expect的代码
full_buffer { #添加对full_buffer匹配的处理;
append outcome \$expect_out(buffer) #在匹配full_buffer的时候,把结果追加到outcome中;
exp_continue #为了保证expect结构可以正常运行,这里需要用exp_continue确保full_buffer处理之后可以继续进行expect的处理;
}
-re "~]" { #这里不建议采用分组的方式,因为分组不合适可能导致部分输出的内容丢失;
append outcome \$expect_out(buffer) #注意这里的append, 不能使用set ,否则会清空outcome中已经有的内容;
}
}
puts \$output \$outcome
send "exit\r"
expect eof
exit
EOF
done
上面代码中,主要是通过 在原来的expect中添加 full_buffer 匹配的处理分支,在full_buffer匹配的时候,把结果追加到自定义的变量中,如果没有遇到full_buffer,那么也会把expect_out的内容转到 自定义变量中;从而通过自定义变量存储所有的输出结果;
上面这段代码获取命令结果的方法才更具有通用性,毕竟很多情况下,我们是无法知道输出大小的,希望可以帮到你哦!
本文原创,转载请注明出处
网友评论