翻译至:http://www.admin-magazine.com/Articles/Automating-with-Expect-Scripts
当然,有些懒的系统管理员懒到一个更高的水平,甚至在编写Expect script上造假,他们通过调用一个名为 Autoexpect 的脚本 “watcher” 或记录脚本来干这事 。 一旦被调用,Autoexpect 观察你的每一个按键,并记录到默认的名为 script.exp 的文件中。你几乎肯定是要编辑和修改这个脚本来实现你想要的结果; 但是,有一个几乎完全工作的脚本可以节省数小时的脚本调试时间。
如果你只是运行一个新创建的Autoexpect脚本,它很可能会失败,因为,如果你通过在在屏幕上显示信息的方式发出一个回答你请求的命令,脚本也会追加这个问题的回答,并把它复制到脚本文件中。
例如,如果在你的Autoexpect会话期间,你键入 ls,该命令的结果会显示在你的 script.exp 文件中。 在你已经手动创建过了一些 Expect 脚本之后,你会明白如何去清理Autoexpect创建的脚本,你必须要这么做。
要安装Autoexpect,使用这样的命令:
$ sudo apt-get install expect-dev
你可能需要安装更多的依赖支持该功能,所以在一切安装完之前等一会儿。
通过Autoexpect创建一个交互式SSH会话
在安装完Autoexpect及其所有必需的包之后,你就可以通过执行你要自动运行的程序来自动创建Expect脚本。 使用上面的例子,SSH到远程系统并运行:
ps -ef |grep apache
命令然后注销。
调用Autoexpect很简单:
$ Autoexpect Autoexpect started, file is script.exp $
虽然看起来好像什么都没发生过,但你键入的每个按键将被记录到script.exp。 你收到的每个标准输出响应也将被复制到同一个文件。你的整个会话会被记录 - 但不仅仅是记录,同时还格式化成Expect风格的脚本。要停止录制按键到你的脚本,在键盘上按Ctrl + D停止 Autoexpect 并拷贝缓冲区到你的文件。
这个简单的程序的完整转录非常长,而且包括了作者 Don Libes 的许多注释:
#!/usr/bin/expect -f # # This Expect script was generated by Autoexpect on Thu Oct 11 15:53:18 2012 # Expect and Autoexpect were both written by Don Libes, NIST. # # Note that Autoexpect does not guarantee a working script. It # necessarily has to guess about certain things. Two reasons a script # might fail are: # # 1) timing - A surprising number of programs (rn, ksh, zsh, telnet, # etc.) and devices discard or ignore keystrokes that arrive "too # quickly" after prompts. If you find your new script hanging up at # one spot, try adding a short sleep just before the previous send. # Setting "force_conservative" to 1 (see below) makes Expect do this # automatically - pausing briefly before sending each character. This # pacifies every program I know of. The -c flag makes the script do # this in the first place. The -C flag allows you to define a # character to toggle this mode off and on. set force_conservative 0 ;# set to 1 to force conservative mode even if ;# script wasn’t run conservatively originally if {$force_conservative} { set send_slow {1 .1} proc send {ignore arg} { sleep .1 exp_send -s -- $arg } } # # 2) differing output - Some programs produce different output each time # they run. The "date" command is an obvious example. Another is # ftp, if it produces throughput statistics at the end of a file # transfer. If this causes a problem, delete these patterns or replace # them with wildcards. An alternative is to use the -p flag (for # "prompt") which makes Expect only look for the last line of output # (i.e., the prompt). The -P flag allows you to define a character to # toggle this mode off and on. # # Read the man page for more info. # # -Don set timeout -1 spawn $env(SHELL) match_max 100000 expect -exact "]0;khess@trapper: ~khess@trapper:~\$ " send -- "ssh aspen\r" expect -exact "ssh aspen\r khess@aspen’s password: " send -- "PASSWORD\r" expect -exact "\r Linux aspen 2.6.32-43-server #97-Ubuntu SMP Wed Sep 5 16:56:41 UTC 2012 x86_64 GNU/Linux\r Ubuntu 10.04.4 LTS\r \r Welcome to the Ubuntu Server!\r * Documentation: http://www.ubuntu.com/server/doc\r \r System information as of Thu Oct 11 15:55:28 CDT 2012\r \r System load: 1.09 Temperature: 40 C\r Usage of /: 1.0% of 454.22GB Processes: 168\r Memory usage: 22% Users logged in: 1\r Swap usage: 0% IP address for eth0: 192.168.1.250\r \r Graph this data and manage this system at https://landscape.canonical.com/\r \r 7 packages can be updated.\r 7 updates are security updates.\r \r New release ‘precise’ available.\r Run ‘do-release-upgrade’ to upgrade to it.\r \r *** System restart required ***\r Last login: Thu Oct 11 15:53:41 2012 from trapper\r\r ]0;khess@aspen: ~khess@aspen:~\$ " send -- "ps -ef|grep apache\r" expect -exact "ps -ef|grep apache\r www-data 555 23171 0 Oct07 ? 00:00:00 /usr/sbin/apache2 -k start\r www-data 556 23171 0 Oct07 ? 00:00:00 /usr/sbin/apache2 -k start\r www-data 557 23171 0 Oct07 ? 00:00:00 /usr/sbin/apache2 -k start\r www-data 558 23171 0 Oct07 ? 00:00:00 /usr/sbin/apache2 -k start\r www-data 559 23171 0 Oct07 ? 00:00:00 /usr/sbin/apache2 -k start\r khess 21504 21433 0 15:55 pts/1 00:00:00 grep apache\r root 23171 1 0 Sep27 ? 00:00:28 /usr/sbin/apache2 -k start\r ]0;khess@aspen: ~khess@aspen:~\$ " send -- "exit\r" expect -exact "exit\r logout\r Connection to aspen closed.\r\r ]0;khess@trapper: ~khess@trapper:~\$ " send -- "^D" expect eof khess@trapper:~$
The parts you needed for this script to execute correctly are shown below in my cleaned up version.
你可以看到,在提炼这份转录到它的基本部分之前你有很多的清理工作为做。 Autoexpect也改变了script.exp 文件的权限,让它是可执行的。
您需要这个脚本能够正确执行的部分如下所示,这是我清理的版本。
#!/usr/bin/expect -f set force_conservative 0 ;# set to 1 to force conservative mode even if ;# script wasn’t run conservatively originally if {$force_conservative} { set send_slow {1 .1} proc send {ignore arg} { sleep .1 exp_send -s -- $arg } } set timeout -1 spawn $env(SHELL) match_max 100000 expect -exact "$ " send -- "ssh aspen\r" expect -exact "password: " send -- "PASSWORD\r" expect -exact "$ " send -- "ps -ef|grep apache\r" expect -exact "$ " send -- "exit\r" expect -exact "$ "
可以看到,复杂的提示,如
expect -exact "exit\r logout\r Connection to aspen closed.\r\r ]0;khess@trapper: ~khess@trapper:~\$ "
已显著缩短为:
expect -exact "$ "
提示仍然有效,因为 Expect 寻找在 expect 行的最后几个字符,而不是整个字符串。你可以缩短密码预期的提示行从:
expect -exact "password: "
到
expect -exact ": "
注意如果缩短你的 expect 行太多的话 - 这会使脚本更加困难,不容易读,以及在将来当您试图弄清楚这是怎么回事时很难解析。 你可能不知道“:”是一个密码提示。 除非你足够聪明在你的脚本中包括注释,你可能会花几个小时的调试这个缩短的版本。