expect-调试模式的使用

时间:2021-10-15 06:28:39

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\r"}
9 expect "Last login" {send "echo test1\r"}
10 expect "*\$*" {send "echo test2\r"}
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\r" to { exp4 }

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

expect: does " \r\n" (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 " \r\nLast login: Sun Nov 25 20:35:43 2018 from 192.168.2.150\r\r\n" (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) " \r\nLast login"
send: sending "echo test1\r" to { exp4 }

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

expect: does ": Sun Nov 25 20:35:43 2018 from 192.168.2.150\r\r\necho test1\r\n" (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\r\r\necho test1\r\n[test@report-server-backup ~]$ echo test1\r\ntest1\r\n[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\r\r\necho test1\r\n[test@report-server-backup ~]$ echo test1\r\ntest1\r\n[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\r\r\necho test1\r\n[test@report-server-backup ~]$ echo test1\r\ntest1\r\n[test@report-server-backup ~]$ "
send: sending "echo test2\r" 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\r" to { exp4 } #执行的动作,发送字符串到exp4

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

  1
2 expect: does " \r\n" (spawn_id exp4) match glob pattern "Last login"? no #expect_out(buffer)变量为\r\n,在进行第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 " \r\nLast login: Sun Nov 25 20:35:43 2018 from 192.168.2.150\r\r\n" (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) " \r\nLast login" #expect_out(buffer)变量的值为“\r\nLast login”
9 send: sending "echo test1\r" 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\r"}
9 expect "*\$*" {send "echo test2\r"}
10 expect "Last login" {send "echo test1\r"}
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”

expect-调试模式的使用

expect-调试模式的使用的更多相关文章

  1. win10 下visual studio 2015 在调试模式下不能跟踪源文件

    win10 下visual studio 2015 在调试模式下不能跟踪源文件,只要一调试就会关闭(隐藏)打开的文档,非常不方便.经过一番折腾,发现是配置的问题. 如果安装多个版本的VS,请删除对应版 ...

  2. 解决ThinkPHP关闭调试模式时报错的问题汇总

    解决ThinkPHP关闭调试模式时报错的问题汇总 案例一: 最近用ThinkPHP开发一个项目,本地开发测试完成上传到服务器后,第一次打开正常,再刷新页面时就出现 "页面调试错误,无法找开页 ...

  3. thinkphp关闭调试模式(APP_DEBUG => false),导致程序出错

    thinkphp关闭调试模式(APP_DEBUG => false),导致程序出错,开启调试模式,不报错,怎么解决? 查看Logs日志记录: [ --29T09::+: ] 113.108.11 ...

  4. [手机取证] 绕过屏幕锁定启用调试模式-For Android 4.4.2

    Google在Android 4.x中引入了调试信任机制,类似于iOS,在设备有屏幕密码的情况下首次连接(或未记住计算机)的情况下, 需要首先打开屏幕锁定后才可进行调试启用操作. 在Android 4 ...

  5. android user版本默认开启调试模式

    由于项目需要,需要发布版本默认开启调试模式,修改方式如下: 1.开启开发者模式 context.getSharedPreferences(DevelopmentSettings.PREF_FILE,C ...

  6. ectouch第九讲 之ectouch 开始调试模式方法

    ectouch 开始调试模式方法 原文: http://my.oschina.net/u/1036767/blog/407067页面报错对于发现编程过程中的问题很重要,所以在开发之前要先搞定它,免得出 ...

  7. 华为p7怎么打开usb调试模式

    在应用程序列表中选择[设置]进入系统设置菜单,点击[关于手机]  2.在"版本号"上面连续点击七次:  3.现在返回"设置"界面,发现多了一个"开 ...

  8. VS Bug 当获取其他项目的代码时, F5 无法进入调试模式. 也不报错....

    在64位的机子下, 被获用的项目使用X86时会出现. 就会出现   F5 无法进入调试模式. 也不报错.... 打断点也没有用. 在不加入X86项目的代码时, 又可以运行..   解决方案:   检查 ...

  9. 教你50招提升ASP.NET性能(十一):避免在调试模式下运行网站

    (17)Avoid running sites in debug mode 招数17: 避免在调试模式下运行网站 When it comes to ASP.NET, one of the most c ...

  10. 关于IE调试模式下才能显示效果

    要去除console.log() 低版本IE 没有开启调试模式  console.log()会导致报错

随机推荐

  1. HttpModule的认识

    1.asp.net的HTTP请求处理过程 说明: (1).客户端浏览器向服务器发出一个http请求,此请求会被inetinfo.exe进程截获,然后转交给aspnet_isapi.dll进程,接着它又 ...

  2. 如何区分Babel中的stage-0,stage-1,stage-2以及stage-3(二)

    上一篇文章我们介绍了法力无边的stage-0 和 包罗万象的stage-1, 现在我们来介绍下 stage-2 和 stage-3 深藏不露的stage-2 为什么说 stage-2深藏不露呢,因为它 ...

  3. Dataguard之redo传输服务

    一.Data Guard架构 整个Data Guard体系就是围绕三个关键点展开: 日志发送(Redo Send) 日志接收(Redo Receive) 日志应用(Redo Apply) 二.日志发送 ...

  4. YII中路径别名

    路径别名 system:代表framework目录 system.web:代表framework/web目录 zii:代表framework/zii目录 webroot:代表项目下的app目录(htt ...

  5. sort(水题)

    sort Time Limit: 6000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  6. Spring与Quartz的整合实现定时任务调度(转)

    最近在研究Spring中的定时任务功能,最好的办法当然是使用Quartz来实现.对于一个新手来说,花了我不少时间,这里我写个笔记,给大家参考.我使用的是Maven来管理项目,需要的Jar包我给大家贴出 ...

  7. n 个骰子的点数

    把 n 个骰子仍在地上,求点数和为 s 的概率. java: public List<Map.Entry<Integer, Double>> dicesSum(int n) { ...

  8. ubuntu14&sol;16 安装python3-opencv3&lowbar;百度经验

    http://jingyan.baidu.com/article/e4511cf348dac52b845eafc8.html

  9. kindeditor扩展粘贴截图功能&amp&semi;修改图片上传路径并通过webapi上传图片到图片服务器

    前言 kindeditor是一个非常好用的富文本编辑器,它的简单使用我就不再介绍了. 而kindeditor却对图片的处理不够理想. 本篇博文需要解决的问题有两个: kindeditor扩展粘贴图片功 ...

  10. LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程

    LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...