Here Documents 结合expect的使用--(3)

作者: My熊猫眼 | 来源:发表于2019-10-13 13:42 被阅读0次

    在上一节中,我们学习了 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的内容转到 自定义变量中;从而通过自定义变量存储所有的输出结果;

    上面这段代码获取命令结果的方法才更具有通用性,毕竟很多情况下,我们是无法知道输出大小的,希望可以帮到你哦!

    本文原创,转载请注明出处

    相关文章

      网友评论

        本文标题:Here Documents 结合expect的使用--(3)

        本文链接:https://www.haomeiwen.com/subject/kpgcmctx.html