浅谈使用expect实现自动交互式(1)

最近测试服务器的网络稳定性,网络老是不定时自动断开,开发人员也没法判定究竟哪里出问题了,一直反复尝试修改某些参数,使之工作正常,测试过程中反映我们之前用的测试手段,手动过程复杂麻烦,可否考虑写成脚本简化,为此找了些方法,最后发现了shell中的expect,python中的pexpect;下面就谈下最近的使用心得。

python 的可以参考:

http://www.ibm.com/developerworks/cn/linux/l-cn-pexpect2/

http://www.ibm.com/developerworks/cn/linux/l-cn-pexpect1/

linux 参考:

http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=1070390

http://blog.chinaunix.net/space.php?uid=20393955&do=blog&id=345046


1、首先介绍下,

Expect使用Tcl作为语言核心。不仅如此,不管程序是交互和还是非交互的,Expect都能运用。这是一个小语言和Unix的其他工具配合起来产生强大功能的经典例子。

Shell没有提供从一个程序读和向一个程序写的功能。这意味着shell可以运行fsck但只能以牺牲一部分fsck的灵活性做代价。有一些程序根本就不能被执行。比如说,如果没有一个用户接口交互式的提供输入,就没法运行下去。其他还有象Telnet,crypt,su,rlogin等程序无法在shell脚本里面自动执行。还有很多其他的应用程序在设计是也是要求用户输入的。

Expect被设计成专门针和交互式程序的交互。一个Expect程序员可以写一个脚本来描述程序和用户的对话。接着Expect程序可以非交互的运行“交互式”的程序。写交互式程序的脚本和写非交互式程序的脚本一样简单。Expect还可以用于对对话的一部分进行自动化,因为程序的控制可以在键盘和脚本之间进行切换。

Expect语言是基于Tcl的。Tcl实际上是一个子程序库,这些子程序库可以嵌入到程序里从而提供语言服务。 最终的语言有点象一个典型的Shell语言。里面有给变量赋值的set命令,控制程序执行的if,for,continue等命令,还能进行普通的数学和字符串操作。

spawn命令激活一个Unix程序来进行交互式的运行。 

send命令向进程发送字符串。

expect命令等待进程的某些字符串。 

expect支持正规表达式并能同时等待多个字符串,并对每一个字符串执行不同的操作。

expect还能理解一些特殊情况,如超时和遇到文件尾。

2、实例:

下面展示下用expect实现ssh配公钥的一个脚本:

      #!/usr/bin/expect
  4 spawn echo "######running to generate a ssh-public-key######"
  5 spawn ssh-keygen -t rsa
  6 expect " Enter file in which to save the key (/root/.ssh/id_rsa):"
  7 send "\r"

  9  expect "Overwrite (y/n)"
 10 send "y\r"
 11 expect "Enter passphrase (empty for no passphrase):"
 12 send "123456\r"
 13 expect "Enter same passphrase again:"
 14 send "123456\r"
 15 expect eof
 16 exit

输出:

Loong:~/ssh_test# ./ssh_modle.sh
spawn echo ######running to generate a ssh-public-key######
spawn ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
/root/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
df:2f:47:5b:49:df:1e:88:97:b4:d2:77:20:d1:c2:30 root@Loong
The key's randomart image is:
+--[ RSA 2048]----+
|          Eo .   |
|           .+ .  |
|             o   |
|            .... |
|        S   +.=.+|
|         . + *.+=|
|          . +..+o|
|            ..o .|
|             o.  |
+-----------------+
Loong:~/ssh_test#
以上便是使用自动交互的一个实例,类似的还可以进行ftp、ssh、密码修改等交互性的实现;上例中当然没有使用到变量,if分支语句等,想要脚本交互性更好的话,当然可以考虑进行加入;

3、安装:

直接用apt-get install expect  即可;

或者下载    

官网地址:

http://expect.nist.gov

   或:http://expect.sourceforge.net/

4、常识解释:

  1、expect命令介绍

    spawn:启动一个程序或进程

    send:给进程或程序返回结果

    expect:接受程序或进程输出

    interact:使用户处于进程或程序的交互状态

2、linux man中关于expect的用法说明:

5、Usage

Expect reads cmdfile for a list of commands to execute. Expect may also beinvoked implicitly on systems which support the #! notation by marking the script executable, and making the first line in your script:

#!/usr/local/bin/expect -f

Of course, the path must accurately describe where Expect lives. /usr/local/bin is just an example.

The -c flag prefaces a command to be executed before any in the script. The command should be quoted to prevent being broken up by the shell. Thisoption may be used multiple times. Multiple commands may be executed with a single-c by separating them with semicolons. Commands are executed in theorder they appear. (When using Expectk, this option is specified as-command.)

The -d flag enables some diagnostic output, which primarily reports internal activity of commands such asexpect andinteract. Thisflag has the same effect as "exp_internal 1" at the beginning of anExpect script, plus the version ofExpect is printed. (Thestrace command isuseful for tracing statements, and thetrace command is useful for tracing variable assignments.) (When using Expectk, this option is specified as-diag.)

The -D flag enables an interactive debugger. An integer value should follow. The debugger will take control before the next Tcl procedure if thevalue is non-zero or if a ^C is pressed (or a breakpoint is hit, or other appropriate debugger command appears in the script). See the README file or SEE ALSO(below) for more information on the debugger. (When using Expectk, this option is specified as-Debug.)

The -f flag prefaces a file from which to read commands from. The flag itself is optional as it is only useful when using the #! notation (seeabove), so that other arguments may be supplied on the command line. (When using Expectk, this option is specified as -file.)

By default, the command file is read into memory and executed in its entirety. It is occasionally desirable to read files one line at a time. For example,stdin is read this way. In order to force arbitrary files to be handled this way, use the-b flag. (When using Expectk, this option is specified as-buffer.)Notethatstdio-bufferingmaystilltakeplacehoweverthisshouldn'tcauseproblemswhenreadingfromafifoorstdin.

If the string "-" is supplied as a filename, standard input is read instead. (Use "./-" to read from a file actually named "-".)

The -i flag causes Expect to interactively prompt for commands instead of reading them from a file. Prompting is terminated via theexit command or upon EOF. Seeinterpreter (below) for more information. -i is assumed if neither a command file nor-c is used.(When using Expectk, this option is specified as-interactive.)

-- may be used to delimit the end of the options. This is useful if you want to pass an option-like argument to your script without it beinginterpreted byExpect. This can usefully be placed in the #! line to prevent any flag-like interpretation byExpect. For example, the following willleave the original arguments (including the script name) in the variableargv.

#!/usr/local/bin/expect --

Note that the usual getopt(3) andexecve(2) conventions must be observed when adding arguments to the #! line.

The file $exp_library/expect.rc is sourced automatically if present, unless the-N flag is used. (When using Expectk, this option is specified as-NORC.) Immediately after this, the file ~/.expect.rc is sourced automatically, unless the-n flag is used. If the environment variable DOTDIR isdefined, it is treated as a directory and .expect.rc is read from there. (When using Expectk, this option is specified as-norc.) This sourcing occursonly after executing any -c flags.

-v causes Expect to print its version number and exit. (The corresponding flag in Expectk, which uses long flag names, is -version.)

Optional args are constructed into a list and stored in the variable namedargv.argc is initialized to the length of argv.

argv0 is defined to be the name of the script (or binary if no script is used). For example, the following prints out the name of the script and thefirst three arguments:

send_user "$argv0 [lrange $argv 0 2]\n"

中文意思为:

用法:
    Expect通过读取cmdfile(命令文件)来执行一系列指令。只要系统支持“#!“,在Script脚本文件的首行标明“#!/usr
/local/bin/expect –f“,并赋予脚本文件可执行权限,执行脚本文件就可以(隐含方式或是默认)调用Expect。
    当然,上面的路径必须正确地指明Expect解释程序的位置。/usr/local/bin只是一个例子。
    -c 选项用来标明需要在执行脚本内容之前来执行的命令。
      这条命令(-c选项后的命令)应该用引号括起来,以免在执行时被shell分开解释。
      -c选项可能会被反复使用。多条命令可以使用同一个”-c”,命令之间需要用分号隔开。这些命令会按照它们出现的先后顺序执行。(在Expectk中,”-c”相当于”-command”)。
    -d 选项允许输出调试性信息。这些信息主要报告像expect和interact等命令执行时的内部行为。这个选项与写在脚本开头的”exp_internal1”具有同样的效果,同时还会打印出Expect的版本。(strace命令用在跟踪变量声明,trace命令用于跟踪变量的赋值)(在Expectk中,”-d”相当于”-diag”)
    -D选项开启交互调试器。后面必须跟有一个整数值作为参数,当值为非零或是按下CTRL+C的时候(或是遇到断点,或是在脚本中恰好出现其他的调试语句),
调试器会在进行下一次Tcl Procedure前取得控制权。想了解更多信息请参见README文件或是下面的SEE
ALSO。(在Expectk中,这个选项相当于”-Debug”)。
    - f 选项指明从哪个文件中读取命令。这个选项是可选的,因为只有当使用”#!”时它才有可能被用到。而其他选项可以写在命令行中。(在Expectk中,它相当于”-file”)。
    默认情况下,命令文件是全部读入内存一并执行的。但有些时候需要每次只读一行。例如:stdin(标准输入)就是这样读取的。如果强制任意文件以这种方式(每次读一行)执行的话就使用”-b”选项。(在Expectk中,它相当于”-buffer”)。
    如果”-“被一个文件名替代,那么脚本就会用读指定文件的方式来替代从标准输入读的方式。(例如:”./ -“就表示从一个名为”-”的文件中读所需的信息)。
    -i选项使Expect能交互式的提示输入命令,而不是从文件中读取。在遇到文件尾或是执行了exit命令时,提示输入命令终止。要了解更多信息请参见下面的
interpreter。-i选项是假设既不是从一个命令文件读,也没有使用-c选项。(在Expectk中,它相当于”-interactive”)。
    -- 是用来为划定选项尾的。当你需要像使用选项一样传一个参数,但希望这个参数不要被当作选项解释时,就需要用到这个选项。当阻止其他选项时,可以把它放在”#!”行中。例如:下面的例子会让所有参数(包括脚本文件名)都存储在argv中。
    #!/usr/local/bin/expect --
注意:当在”#!”行中使用参数时,必须遵守getopt(3)和execve(2)的规定。
    $exp_library下如果有expect.rc这个文件的话,它会自动被加载为资源文件(应该是类似于标准配置文件,像用户根目录下
的.bash_profile文件一样)。除非使用-N选项取消自动加载。(在Expectk中,它相当于”-NORC”)。这个文件被加载后,紧接着用
户根目录下的.expect.rc(~/.expect.rc)会被加载。除使用-n选项取消。如果定义了环境变量DOTDIR,那么它被认为是存放
有.expect.rc文件的目录。然后从这个目录中读取.expect.rc文件。(在Expectk中,它相当于”-norc”)。这些加载配置文件
的动作是出现在执行完-c选项指定的命令之后。
    -v 选项用来打印出版本号,然后退出。(在Expectk中的相应选项是-version)。
    可选的参数汇成一列,存放在变量argv中。Argc被初始化为argv的长度(变量个数)。Argv0被设置为脚本名称(or binary if no script is used)。例如:下面的例子打印出脚本的名称和前三个参数。
    Send_user “$argv0 [lrang $argv 0 2 ]\n”

6、Commands

Expect uses Tcl (Tool Command Language). Tcl provides control flow (e.g., if, for,break), expression evaluation and several other features such as recursion, procedure definition, etc. Commands used here but not defined (e.g., set, if, exec) are Tcl commands (see tcl(3)). Expect supports additional commands, described below. Unless otherwise specified, commandsreturn the empty string.

Commands are listed alphabetically so that they can be quickly located. However, new users may find it easier to start by reading the descriptions ofspawn,send,expect, andinteract, in that order.

Note that the best introduction to the language (both Expect and Tcl) is provided in the book "Exploring Expect" (see SEE ALSO below). Examples are includedin this man page but they are very limited since this man page is meant primarily as reference material.

Note that in the text of this man page, "Expect" with an uppercase "E" refers to theExpect program while "expect" with a lower-case "e" refers totheexpect command within the Expect program.)

close [-slave] [-onexec 0|1] [-i spawn_id]
closes the connection to the current process. Most interactive programs will detect EOF on their stdin and exit; thus close usually suffices to killthe process as well. The -i flag declares the process to close corresponding to the named spawn_id.

Both expect and interact will detect when the current process exits and implicitly do aclose. But if you kill the process by, say,"exec kill $pid", you will need to explicitly callclose.

The -onexec flag determines whether the spawn id will be closed in any new spawned processes or if the process is overlayed. To leave a spawn idopen, use the value 0. A non-zero integer value will force the spawn closed (the default) in any new processes.

The -slave flag closes the slave associated with the spawn id. (See "spawn -pty".) When the connection is closed, the slave is automatically closedas well if still open.

No matter whether the connection is closed implicitly or explicitly, you should callwait to clear up the corresponding kernel process slot.close does not callwait since there is no guarantee that closing a process connection will cause it to exit. Seewait below for moreinfo.

debug [[-now] 0|1]
controls a Tcl debugger allowing you to step through statements, set breakpoints, etc.

With no arguments, a 1 is returned if the debugger is not running, otherwise a 0 is returned.

With a 1 argument, the debugger is started. With a 0 argument, the debugger is stopped. If a 1 argument is preceded by the-now flag, the debugger isstarted immediately (i.e., in the middle of thedebug command itself). Otherwise, the debugger is started with the next Tcl statement.

The debug command does not change any traps. Compare this to startingExpect with the-D flag (see above).

See the README file or SEE ALSO (below) for more information on the debugger.

disconnect
disconnects a forked process from the terminal. It continues running in the background. The process is given its own process group (if possible). StandardI/O is redirected to /dev/null.
The following fragment uses
disconnect to continue running the script in the background.
if {[fork]!=0} exit
disconnect
. . .
The following script reads a password, and then runs a program every hour that demands a password each time it is run. The script supplies the password so thatyou only have to type it once. (See the stty command which demonstrates how to turn off password echoing.)
send_user "password?\ "
expect_user -re "(.*)\n"
for {} 1 {} {
    if {[fork]!=0} 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值