一、概述
我们通过Shell可以实现简单的控制流功能,如:循环、判断等。但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能。而Expect就使用来实现这种功能的工具。
Expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。Expect的作者Don Libes在1990年开始编写Expect时对Expect做有如下定义:Expect是一个用来实现自动交互功能的软件套件 (Expect [is a] software suite for automating interactive tools)。使用它系统管理员 的可以创建脚本用来实现对命令或程序提供输入,而这些命令和程序是期望从终端(terminal)得到输入,一般来说这些输入都需要手工输入进行的。 Expect则可以根据程序的提示模拟标准输入提供给程序需要的输入来实现交互程序执行。甚至可以实现实现简单的BBS聊天机器人。:)
Expect是不断发展的,随着时间的流逝,其功能越来越强大,已经成为系统管理员的的一个强大助手。Expect需要Tcl编程语言的支持,要在系统上运行Expect必须首先安装Tcl。
二、Expect工作原理
从最简单的层次来说,Expect的工作方式象一个通用化的Chat脚本工具。Chat脚本最早用于UUCP网络内,以用来实现计算机之间需要建立连接时进行特定的登录会话的自动化。Chat脚本由一系列expect-send对组成:expect等待输出中输出特定的字符,通常是一个提示符,然后发送特定的响应。
expect用法
#!/usr/bin/expect
set timeout 30
spawn ssh -l username 192.168.1.1
expect “password:”
send “ispass/r”
interact
1. [#!/usr/bin/expect]
这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。
注意:这一行需要在脚本的第一行。
2. [set timeout 30]
“set 自定义变量名”:设置超时时间的,现在你只要记住他的计时单位是:秒 。timeout -1 为永不超时
3. [spawn ssh -l username 192.168.1.1]
spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。
它主要的功能是给ssh运行进程加个壳,用来传递交互指令。可以理解为启动一个新进程
4. [expect “password:”]
从进程接收字符串,这里的expect是expect的一个内部命令,expect的shell命令和内部命令是一样的,但不是一个功能。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的30秒;
5. [send “ispass/r”]
send接收一个字符串参数,并将该参数发送到进程。这里就是执行交互动作,与手工输入密码的动作等效。 命令字符串结尾别忘记加上“/r”,表示“回车键”。
6. [interact]
允许用户交互;执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。
7.$argv 参数数组
expect脚本可以接受从bash传递过来的参数.可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个….参数
7. 下面的expect脚本的例子
执行这个文件./launch.exp 1 2 3
屏幕上就会分别打印出参数
send_user用来发送内容给用户。
参数运用方面还有很多技巧
比如$argc 存储了参数个数,args被结构化成一个列表存在argv。$argv0 被初始化为脚本名字。
除此之外,如果你在第一行(#!那行)使用-d (debug参数),可以在运行的时候输出一些很有用的信息
比如你会看见
argv[0] = /usr/bin/expect argv[1] = -d argv[2] = ./launch.exp argv[3] = 1 argv[4] = 2 argv[5] = 3
使用这些也可以完成参数传递
8.
expect的命令行参数参考了c语言的,与bash shell有点不一样。其中,$argc为命令行参数的个数,$argv0为脚本名字本身,$argv为命令行参数。[lrange $argv 0 0]表示第1个参数,[lrange $argv 0 4]为第一个到第五个参数。与c语言不一样的地方在于,$argv不包含脚本名字本身。
9.
exp_continue的用法
#!/usr/bin/expect -f
set ipaddr “localhost”
set passwd “iforgot”
spawn ssh root@$ipaddr #spawn 意思是执行命令,expect内命令,shell中不存在
expect {
”yes/no” { send “yes/r”; exp_continue}
”password:” { send “$passwd/r” }
}
expect “]# “
send “touch a.txt/r” #意思为发送命令
send “exit/r”
expect eof
exit
几个例子:
1、
expect最常用的语法是来自tcl语言的模式-动作。这种语法极其灵活,下面我们就各种语法分别说明。
单一分支模式语法:
expect "hi" {send "You said hi"}
匹配到hi后,会输出”you said hi”
多分支模式语法:
expect "hi" { send "You said hi/n" } / "hello" { send "Hello yourself/n" } / "bye" { send "dat was unexpected/n" }
匹配到hi,hello,bye任意一个字符串时,执行相应的输出。等同于如下写法:
expect {
"hi" { send "You said hi/n"} "hello" { send "Hello yourself/n"} "bye" { send "That was unexpected/n"} }
2、
所有demo都是和标准输入输出进行交互,但是我们跟希望他可以和某一个进程进行交互。spawm命令就是用来启动新的进程的。spawn后的send和expect命令都是和spawn打开的进程进行交互的。结合上文的send和expect命令我们可以看一下更复杂的程序段了。
set timeout -1 spawn ftp ftp.test.com //打开新的进程,该进程用户连接远程ftp服务器 expect "Name" //进程返回Name时 send "user/r" //向进程输入anonymous/r expect "Password:" //进程返回Password:时 send "123456/r" [email protected]/r expect "ftp> " //进程返回ftp>时 send "binary/r" //向进程输入binary/r expect "ftp> " //进程返回ftp>时 send "get test.tar.gz/r" //向进程输入get test.tar.gz/r
这段代码的作用是登录到ftp服务器ftp ftp.uu.net上,并以二进制的方式下载服务器上的文件test.tar.gz。程序中有详细的注释。
下载完ftp文件时,仍然可以停留在ftp命令行状态,以便手动的执行后续命令。interact可以达到这些目的。下面的demo在自动登录ftp后,允许用户交互。
spawn ftp ftp.test.com expect "Name" send "user/r" expect "Password:" send "123456/r" interact
4、
下面一段脚本实现了从机器A登录到机器B,然后执行机器B上的pwd命令,并停留在B机器上,等待用户交互。
#!/home/tools/bin/64/expect -f
set timeout -1 spawn ssh $BUser@$BHost expect "*password:" { send "$password/r" } expect "$*" { send "pwd/r" } interact
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/1851.html