expect介绍
expect
是一个自动交互功能的工具。expect
命令会新建一个子进程,通过spawn
来执行shell
脚本,监测脚本的返回结果,然后通过expect
判断要进行的交互输入内容。
借助Expect
处理交互的命令,可以将交互 过程如:ssh
登录,ftp
登录等写在一个脚本上,使之自动化完成.尤其适用于需 要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率 。
expect
安装
Expect
是一个基于TCL
开发出的语言包。系统一般不会自带,需要自行安装。
TCL(Tool Command Language)工具脚本语言,是Linux内的一种语言包。
系统为RHEL/CentOS
:
yum install expect
系统为Debian/Ubuntu
:
apt-get install expect
expect
脚本
expect
脚本以#!/usr/bin/expect
开头,用来告诉操作系统脚本里的代码使用那一个shell
来执行。这里的expect
和linux
下的bash
、windows
下的cmd
是一类东西。
以.exp或者.ex结束,通过./xxx.exp
运行(需要可执行权限),类似bash
脚本。
也可以以
sh
结尾,通过expect ./xx.sh
执行,如expect ./auto_deploy.sh
。
expect
命令选项
expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
选项
-
-v
:显示expect
版本信息。 -
-f
:从文件读取命令,仅用于使用#!
时。如果文件名为file
,则从stdin
读取(使用./file
从文件名为file
的文件读取)。 -
-c
:从命令行执行expect
脚本,默认expect
是交互地执行的,如下所示:expect -c 'expect "\n" {send "pressed enter\n"}
如果你执行了上面的脚本,它会等待输入换行符
\n
。按enter
键以后,它会打印出pressed enter
这个消息,然后退出。 -
-i
:使用-i
选项,可以通过来自于标准输入的读命令来交互地执行expect
脚本。如下所示:expect -i arg1 arg2 arg3 expect1.1>set argv arg1 arg2 arg3 expect1.2>
正常情况下,当你执行上面的
expect
命令的时候(没有-i
选项),它会把arg1
当成脚本的文件名,所以-i
选项可以让脚本把多个参数当成一个连续的列表。 -
-d
:可以输出输出调试信息$ cat sample.exp # !/usr/bin/expect -f expect “\n”; send “pressed enter”; $ expect -d sample.exp expect version 5.43.0 argv[0] = expect argv[1] = -d argv[2] = sample.exp set argc 0 set argv0 “sample.exp” set argv “” executing commands from command file sample.exp expect: does “” (spawn_id exp0) match glob pattern “\n”? no expect: does “\n” (spawn_id exp0) match glob pattern “\n”? yes expect: set expect_out(0,string) “\n” expect: set expect_out(spawn_id) “exp0” expect: set expect_out(buffer) “\n” send: sending “pressed enter” to { exp0 pressed enter}
-
-b
: 通常,expect
会在执行脚本之前,把整个脚本都读入到内存中。-b
选项可以让expect
一次只读取脚本中的一行。当你没有写完整个脚本的时候,这是十分有用的,expect
可以开始执行这个不完整的脚本。expect -b
-
-d
:让expect
不解释命令行参数你可以使用标识符让
expect
不解释命令行参数。你可以像下面这样的读入命令行参数:$ cat print_cmdline_args.exp #!/usr/bin/expect puts ‘argv0 : [lindex $argv 0]’; puts ‘argv1 : [lindex $argv 1]’;
当执行上面的脚本的时候,会跳过命令行选项,它们会被当成参数(而不是
expect
选项),如下所示:$ expect print_cmdline_args.exp -d -c argv0 : -d argv1 : -c
expect
内置命令
-
set timeout
: 设置超时时间的,单位是:秒 。例如:set timeout 30
# 永远等待,不会超时 set timeout -1
-
spawn
:spawn
是进入expect
环境后才可以执行的expect
内部命令,如果没有装expect
或者直接在默认的SHELL
下执行是找不到spawn
命令的。所以不要用which spawn
之类的命令去找spawn
命令。spawn
用来启动新的进程的,spawn
后的send
和expect
命令都是和spawn
打开的进程进行交互的。# 直接运行一个 bash 脚本 spawn /mnt/sh_expect.sh # 直接运行一个 bash 命令 spawn ssh -p ${port} $user@$host
-
send
:用于向进程发送命令字符串 ,这里就是执行交互动作,与手工输入的动作等效。 命令字符串结尾别忘记加上\n
。 -
expect
:expect
也是expect
的一个内部命令,expect
的shell
命令和内部命令是一样的,但不是一个功能。这个命令的意思是判断上次输出结果里是否包含指定的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是set timeout xxx
设置的时间。# 从标准输入中等到hi和换行键后,向标准输出输出hello there expect "hi\n" send "hello there!\n" # 退出 spawn 会话,返回当前的shell进程 send "exit\n" # 退出expect expect eof
-
interact
:从自动交互状态退出到输入状态,由用户完成剩余的操作.,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。 -
exp_continue
:重置set timeout
设置的时间,重新执行当前expect
分支# 如果匹配到*assword,那么发送密码,并进入下面的expect语句(uname -a语句)。 # 如果匹配到yes/no,那么发送yes,并重新执行这个expect分支语句。 expect { "*assword" {send "123456\r";} "yes/no" {send "yes\r";exp_continue} }
命令行参数
$argc,$argv 0,$argv 1 ... $argv n
argc
表示命令行参数个数,后面分别表示各个参数项,0表示第一个参数,1表示第二个参数,以此类推,可以通过lindex
获取对应参数值[lrange $argv 0 0]
。
if {$argc < 2} {
puts stdout "$argv0 err params\n"
exit 1
}
set user [lindex $argv 0]
set password [lindex $argv 1]
参数存在argv
当中,[lrange $argv 0 0]
表示第1
个参数,[lrange $argv 0 4]
为第一个到第五个参数。如果需要计算的话必须用expr
,如计算2-1
,则必须用[expr 2-1]
;
语法
expect
遵循tcl
的语法规范,基础语法部分可以查看这里,循环、条件判断、各种运算符都有详细的说明