在上一篇文章中,我们讨论了写作实用的shell脚本,我们看到了编写 shell 脚本是多么容易。今天我们要讨论一个对 shell 脚本有神奇作用的工具;该工具是期待命令 or 期待脚本语言.
Expect 命令或 Expect 脚本语言是一种与需要用户交互的交互式程序或脚本进行对话的语言。
Expect 脚本语言的工作方式是等待输入,然后 Expect 脚本将发送响应,而无需任何用户交互。
您可以说这个工具是您的机器人,它将自动执行您的脚本。
如果您的系统上未安装expect命令,您可以使用以下命令安装它:
$ apt-get install expect
或者在基于 Red Hat 的系统(例如 CentOS)上:
$ yum install expect
期待命令
在我们讨论expect命令之前,我们先来看看Expect的一些用于交互的命令:
spawn |
Starts a script or a program. |
expect |
Waits for program output. |
send |
Sends a reply to your program. |
interact |
Allows you to interact with your program. |
- spawn 命令启动一个脚本或一个像 shell 一样的程序,FTP、Telnet、SSH、SCP 等。
- 发送命令发送对脚本或程序的答复。
- Expect 命令等待输入。
- 交互命令允许您定义预定义的用户交互。
我们将输入一个询问一些问题的 shell 脚本,然后我们将创建一个 Expect 脚本来回答这些问题。
首先,shell 脚本如下所示:
#!/bin/bash
echo "Hello, who are you?"
read $REPLY
echo "Can I ask you some questions?"
read $REPLY
echo "What is your favorite topic?"
read $REPLY
现在我们将编写 Expect 脚本来自动回答这个问题:
#!/usr/bin/expect -f
set timeout -1
spawn ./questions
expect "Hello, who are you?\r"
send -- "Im Adam\r"
expect "Can I ask you some questions?\r"
send -- "Sure\r"
expect "What is your favorite topic?\r"
send -- "Technology\r"
expect eof
第一行定义了期望的命令路径,即
#!/usr/bin/expect
在第二行代码中,我们禁用超时。然后使用spawn命令启动我们的脚本。
我们可以使用spawn来运行任何我们想要的程序或任何其他交互式脚本。
其余行是与我们的 shell 脚本交互的 Expect 脚本。
最后一行表示交互结束。
现在 Showtime,让我们运行我们的应答机器人并确保使其可执行。
$ chmod +x ./answerbot
$./answerbot
凉爽的!!发送命令回答了所有问题。
如果您收到有关 Expect 命令位置的错误,您可以使用which 命令获取位置:
$ which expect
我们根本没有与我们的脚本进行交互; Expect 程序为我们完成了这项工作。
您可以将上述方法应用于任何交互式脚本或程序。虽然上面的 Expect 脚本很容易编写,但也许 Expect 脚本对某些人来说有点棘手,好吧,你已经有了。
自动执行交互式命令
The -c
选项expect
允许您提供expect
直接从命令行而不是从文件命令。
假设您想要生成一个 shell,等待 shell 提示符,然后发送命令whoami
:
expect -c 'spawn /bin/bash; expect "$ "; send "whoami\n"'
First, spawn /bin/bash
启动一个新的 shell 实例。
然后,expect "$ "
等待 shell 出现其典型提示符,通常表示为$
对于普通用户。
一旦脚本识别出此提示,send "whoami\n"
指示脚本输入whoami
命令进入 shell,后跟换行符(表示为\n
),相当于按“Enter”键。
结果与手动输入的结果相同whoami
命令进入 shell 以查找当前登录用户的名称。
使用自动预期
要自动构建expect脚本,可以使用autoexpect命令。
autoexpect 的工作方式与 Expect 命令类似,但它会为您构建自动化脚本。您将要自动化的脚本作为参数传递给 autoexpect,然后回答问题,autoexpect 会将您的答案保存在文件中。
$ autoexpect ./questions
autoexpect 生成一个名为 script.exp 的文件,其中包含与上面相同的代码,并添加了一些内容,我们暂时保留它。
如果运行自动生成的文件 script.exp,您将看到与预期相同的答案:
惊人的!!那超级简单。
许多命令会产生可变的输出,例如 FTP 程序的情况,expect 脚本可能会失败或卡住。为了解决这个问题,您可以对可更改的数据使用通配符,以使脚本更加灵活。
使用变量
您可以使用 set 命令在 Expect 脚本中定义变量,如下所示:
set MYVAR 5
要访问该变量,请在其前面加上 $,如下所示 $VAR1
要在 Expect 脚本中定义命令行参数,我们使用以下语法:
set MYVAR [lindex $argv 0]
这里我们定义了一个变量 MYVAR,它等于第一个传递的参数。
您可以获取第一个和第二个参数并将它们存储在变量中,如下所示:
set my_name [lindex $argv 0]
set my_favorite [lindex $argv 1]
让我们向脚本添加变量:
#!/usr/bin/expect -f
set my_name [lindex $argv 0]
set my_favorite [lindex $argv 1]
set timeout -1
spawn ./questions
expect "Hello, who are you?\r"
send -- "Im $my_name\r"
expect "Can I ask you some questions?\r"
send -- "Sure\r"
expect "What is your favorite topic?\r"
send -- "$my_favorite\r"
expect eof
现在尝试使用一些参数运行 Expect 脚本以查看输出:
$ ./answerbot SomeName Programming
惊人的!!现在我们的自动化 Expect 脚本更加动态。
条件测试
您可以使用大括号编写条件测试,如下所示:
expect {
"something" { send -- "send this\r" }
"*another" { send -- "send another\r" }
}
我们将更改我们的脚本以返回不同的条件,并且我们将更改我们的 Expect 脚本来处理这些条件。
我们将使用以下脚本来模拟不同的期望:
#!/bin/bash
let number=$RANDOM
if [ $number -gt 25000 ]; then
echo "What is your favorite topic?"
else
echo "What is your favorite movie?"
fi
read $REPLY
当您运行脚本时,它每次都会生成一个随机数,并基于该数字;我们设置了一个条件来返回不同的期望。
让我们制定出处理这个问题的 Expect 脚本。
#!/usr/bin/expect -f
set timeout -1
spawn ./questions
expect {
"*topic?" { send -- "Programming\r" }
"*movie?" { send -- "Star wars\r" }
}
expect eof
非常清楚。如果脚本命中主题输出,则expect脚本将发送节目,如果脚本命中电影输出,则expect脚本将发送星球大战。是不是很酷?
如果是其他条件
您可以在 Expect 脚本中使用 if/else 子句,如下所示:
#!/usr/bin/expect -f
set NUM 1
if { $NUM < 5 } {
puts "\Smaller than 5\n"
} elseif { $NUM > 5 } {
puts "\Bigger than 5\n"
} else {
puts "\Equals 5\n"
}
Note: 左大括号必须在同一行.
While 循环
Expect 语言中的 while 循环必须使用大括号来包含如下表达式:
#!/usr/bin/expect -f
set NUM 0
while { $NUM <= 5 } {
puts "\nNumber is $NUM"
set NUM [ expr $NUM + 1 ]
}
puts ""
For 循环
与任何脚本或编程语言一样,您可以使用 for 循环执行重复任务,必须指定三个字段,如下格式:
#!/usr/bin/expect -f
for {set NUM 0} {$NUM <= 5} {incr NUM} {
puts "\nNUM = $NUM"
}
puts ""
用户定义函数
您可以使用 proc 定义一个函数,如下所示:
proc myfunc { TOTAL } {
set TOTAL [expr $TOTAL + 1]
return "$TOTAL"
}
之后您就可以使用它们。
#!/usr/bin/expect -f
proc myfunc { TOTAL } {
set TOTAL [expr $TOTAL + 1]
return "$TOTAL"
}
set NUM 0
while {$NUM <= 5} {
puts "\nNumber $NUM"
set NUM [myfunc $NUM]
}
puts ""
交互命令
有时,您的期望脚本包含一些您不想与使用您的期望脚本的其他用户共享的敏感信息,例如密码或任何其他数据。因此,您希望脚本从您那里获取此密码并正常继续自动化。
交互命令将控制权恢复给键盘。
当您使用交互命令时,expect 将开始从键盘读取。
此 shell 脚本将询问密码,如下所示:
#!/bin/bash
echo "Hello, who are you?"
read $REPLY
echo "What is you password?"
read $REPLY
echo "What is your favorite topic?"
read $REPLY
现在我们将编写提示输入密码的 Expect 脚本:
#!/usr/bin/expect -f
set timeout -1
spawn ./questions
expect "Hello, who are you?\r"
send -- "Hi Im Adam\r"
expect "*password?\r"
interact ++ return
send "\r"
expect "*topic?\r"
send -- "Technology\r"
expect eof
输入密码后,输入 ++,控件将从键盘返回到脚本。
由于其简单性和重要性,Expect 语言被移植到许多语言,如 C#、Java、Perl、Python、Ruby 和 Shell,具有几乎相同的概念和语法。
您可以在质量保证、网络测量(例如回显响应时间)、自动文件传输、更新和许多其他用途中使用 Expect 脚本语言。
我希望您现在已经了解了 Expect 命令、autoexpect 命令的一些最重要的方面,以及如何使用它以更智能的方式自动执行任务。
谢谢。