zoukankan      html  css  js  c++  java
  • expect-调试模式的使用

    1、expect简介

    Expect是一种TCL扩展性的语言,主要用于完成系统交互方面的功能,比如SSH、FTP等,这些程序都需要手工与它们进行互动,而使用Expect就可以模拟人手工互动的过程,是一种自动的方式控制。

    在使用shell编写巡检脚本的过程中,常使用expect工具与巡检机器进行交互。通常我们在碰到expect脚本异常的时候,这就需要使用到调试模式来具体分析。

    2、安装与打开调试模式

    配置好yum后,安装命令如下

    yum install expect

    调试模式的开启

    • 打开debug模式,使用-d,可以方便调试并且观看expect的执行过程
    • exp_internal

    这是一条用来打开Expect调试模式的命令,它可以将整个匹配,操作过程中间发生的事情显示出来,它接受的值包括:非0值(打开调试模式)、0(关闭调试模式)、-f file(将调试内容写入文件)

    3、从一个简单的脚本开始

      1 #!/usr/bin/expect -d
      2 #written by ahao
      3 #注意,在spawn中,如果要注释的话,另外起一行,放在代码的后面会有问题,这点与bash不一样
      4 set timeout 10
      5 spawn -noecho ssh -o StrictHostKeyChecking=no -l test 192.168.2.151 -p 22
      6 #spawn命令是expect的初始命令,他用于启动一个进程,之后所有操作都在这个进程中进行,如果没有spawn,这个expect都无法进行
      7 #StrictHostKeyChecking=no参数让ssh默认添加新主机的公钥指纹,也就不会出现出现是否继续yes/no的提示了
      8 expect "password:" {send "123456
    "}
      9 expect "Last login" {send "echo test1
    "}
     10 expect "*$*" {send "echo test2
    "}
     11 expect eof
     12 #EOF(End Of File),表示"文字流"(stream)的结尾。这里的"文字流",可以是文件(file),也可以是标准输入(stdin),EOF是不可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于EOF时,表示读入的已不是正常的字符而是文件结束符,但这适用对文本文件的读写
     13 #也就是说eof通常定义为-1,在本文文件中数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~255,不可能出现-1,因此可以用EOF作为文件结束标志,如果处理时返回-1的值,那就eof

    注:脚本中有4个expect过程

    • 第一个expect:匹配到输入密码的提示,输入密码
    • 第二个expect:输入密码后会有上次登录的一个信息,匹配”Last login”后执行一个echo命令
    • 第三个expect:执行echo命令完成后,匹配提示符”$”后再执行一个echo命令
    • 第四个expect命令:匹配eof

    整个执行过程如下:1-3expect过程分别使用不同颜色标识

    [patrol@report-server db_bin]$ ./auto_login.sh
    expect version 5.44.1.15
    argv[0] = /usr/bin/expect  argv[1] = -d  argv[2] = ./auto_login.sh 
    set argc 0
    set argv0 "./auto_login.sh"
    set argv ""
    executing commands from command file ./auto_login.sh
    parent: waiting for sync byte
    parent: telling child to go ahead
    parent: now unsynchronized from child
    spawn: returns {121224}

    expect: does "" (spawn_id exp4) match glob pattern "password:"? no
    test@192.168.2.151's password:
    expect: does "test@192.168.2.151's password: " (spawn_id exp4) match glob pattern "password:"? yes
    expect: set expect_out(0,string) "password:"
    expect: set expect_out(spawn_id) "exp4"
    expect: set expect_out(buffer) "test@192.168.2.151's password:"
    send: sending "123456 " to { exp4 }

    expect: does " " (spawn_id exp4) match glob pattern "Last login"? no


    expect: does " " (spawn_id exp4) match glob pattern "Last login"? no
    Last login: Sun Nov 25 20:35:43 2018 from 192.168.2.150

    expect: does " Last login: Sun Nov 25 20:35:43 2018 from 192.168.2.150 " (spawn_id exp4) match glob pattern "Last login"? yes
    expect: set expect_out(0,string) "Last login"
    expect: set expect_out(spawn_id) "exp4"
    expect: set expect_out(buffer) " Last login"
    send: sending "echo test1 " to { exp4 }

    expect: does ": Sun Nov 25 20:35:43 2018 from 192.168.2.150 " (spawn_id exp4) match glob pattern "*$*"? no
    echo test1

    expect: does ": Sun Nov 25 20:35:43 2018 from 192.168.2.150 echo test1 " (spawn_id exp4) match glob pattern "*$*"? no
    [test@report-server-backup ~]$ echo test1
    test1
    [test@report-server-backup ~]$
    expect: does ": Sun Nov 25 20:35:43 2018 from 192.168.2.150 echo test1 [test@report-server-backup ~]$ echo test1 test1 [test@report-server-backup ~]$ " (spawn_id exp4) match glob pattern "*$*"? yes
    expect: set expect_out(0,string) ": Sun Nov 25 20:35:43 2018 from 192.168.2.150 echo test1 [test@report-server-backup ~]$ echo test1 test1 [test@report-server-backup ~]$ "
    expect: set expect_out(spawn_id) "exp4"
    expect: set expect_out(buffer) ": Sun Nov 25 20:35:43 2018 from 192.168.2.150 echo test1 [test@report-server-backup ~]$ echo test1 test1 [test@report-server-backup ~]$ "
    send: sending "echo test2 " to { exp4 }

    echo test2
    test2
    [test@report-server-backup ~]$ expect: timed out
    [patrol@report-server db_bin]$

    为了对比分析,把调试模式关闭,整个输出如下

    [patrol@report-server db_bin]$ ./auto_login.sh
    test@192.168.2.151's password:
    Last login: Sun Nov 25 20:38:03 2018 from 192.168.2.150
    echo test1
    [test@report-server-backup ~]$ echo test1
    test1
    [test@report-server-backup ~]$ echo test2
    test2

    4、过程分析

    首先了解一下expect_out数组,expect_out数组专用与expect命令,里面的元素包括:

    expect_out(buffer)、expect_out(X,string)、expect_out(X,start)、expect_out(X,end)、expect_out(spawn_id)

    上面的X字符表示从0-9的整数,具体如下

    • expect_out(buffer)是一个看起来比较特殊的变量,这个变量中放置从上一次匹配到这一次匹配之间的所有返回,包括匹配字符本身。----重点
    • expect_out(x,string):x是一个数字,从0到9,加起来一共是10个变量,其中0变量比较特殊,它里面保存整个expect正则表达式中匹配到的所有内容,而从1开始到9的变量中,保存正则表达式中子模式的值,也就是括在()中的那部分内容,从左往右计算
    • expect_out(x,start|end):x与上面的含义相同,这个变量的值是一个数值,以expect_out(1,start)为例,它里面保存第一个子模式在expect_out(buffer)变量中匹配到的时候的索引值,比如第一个子模式匹配是在expect_out(buffer)中的第10个字符开始匹配到的,那么这个变量的值就是10

    结合上面的的第1个expect过程进行解析:

      1 expect: does "" (spawn_id exp4) match glob pattern "password:"? no   #no代表匹配不成功,expect: does执行匹配动作,对捕捉到的字符串匹配”password:”,没匹配成功
      2  test@192.168.2.151's password:                   #输出
      3  expect: does "test@192.168.2.151's password: " (spawn_id exp4) match glob pattern "password:"? yes   #yes代表匹配成功,expect: does执行匹配动作,对捕捉到的"test@192.168.2.151's password: "进行匹配,匹配成功后,下面输出相关信息与动作
      4  expect: set expect_out(0,string) "password:"           #匹配到的字符串为”password”
      5  expect: set expect_out(spawn_id) "exp4"             #spawn_id进程为exp4
      6  expect: set expect_out(buffer) "test@192.168.2.151's password:"   #expect_out(buffer)变量的信息:test@192.168.2.151's password:
      7  send: sending "123456
    " to { exp4 }  #执行的动作,发送字符串到exp4

    结合上面的第2个expect过程进行解析:

      1 
      2  expect: does " 
    " (spawn_id exp4) match glob pattern "Last login"? no  #expect_out(buffer)变量为
    ,在进行第2次expect的时候,expect_out(buffer)变量是不包含第一次匹配的字符串的
      3  Last login: Sun Nov 25 20:35:43 2018 from 192.168.2.150    #上一个expect_send后的输出
      4 
      5 expect: does " 
    Last login: Sun Nov 25 20:35:43 2018 from 192.168.2.150
    
    " (spawn_id exp4) match glob pattern "Last login"? yes               #匹配了,下面开始相关信息的输出与执行下一步的动作
      6  expect: set expect_out(0,string) "Last login"   #匹配到的字符串
      7  expect: set expect_out(spawn_id) "exp4"
      8  expect: set expect_out(buffer) " 
    Last login"  #expect_out(buffer)变量的值为“
    Last login”
      9  send: sending "echo test1
    " to { exp4 }  #发送命令到exp4

    第3个expect分析:略

    5、思考一个问题

    第二个expect和第三个expect顺序调转下,会是啥结果?如下代码:

      1 #!/usr/bin/expect
      2 #written by ahao
      3 #注意,在spawn中,如果要注释的话,另外起一行,放在代码的后面会有问题,这点与bash不一样
      4 set timeout 10
      5 spawn -noecho ssh -o StrictHostKeyChecking=no -l test 192.168.2.151 -p 22
      6 #spawn命令是expect的初始命令,他用于启动一个进程,之后所有操作都在这个进程中进行,如果没有spawn,这个expect都无法进行
      7 #StrictHostKeyChecking=no参数让ssh默认添加新主机的公钥指纹,也就不会出现出现是否继续yes/no的提示了
      8 expect "password:" {send "123456
    "}
      9 expect "*$*" {send "echo test2
    "}
     10 expect "Last login" {send "echo test1
    "}
     11 expect eof
     12 #EOF(End Of File),表示"文字流"(stream)的结尾。这里的"文字流",可以是文件(file),也可以是标准输入(stdin),EOF是不可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于EOF时,表示读入的已不是正常的字符而是文件结束符,但这适用对文本文件的读写
     13 #也就是说eof通常定义为-1,在本文文件中数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~255,不可能出现-1,因此可以用EOF作为文件结束标志,如果处理时返回-1的值,那就eof

    结果就是:第三个expect不可能匹配成功, expect_out(buffer)变量已不可能包含关键字”Last login

    image

  • 相关阅读:
    【转】C#操作Word的超详细总结
    【转】C#操作word定位光标
    详解Amazon S3上传/下载数据
    VS2010程序崩溃- APPCRASH
    环境搭建
    centos搭建svn服务器
    SpringMVC必备知识点汇总
    SpringSecurity 配置
    数据库汇总
    java.io.IOException 断开的管道 解决方法 ClientAbortException: java.io.IOException: Broken pipe
  • 原文地址:https://www.cnblogs.com/fuqu/p/10017763.html
Copyright © 2011-2022 走看看