Expect 命令以及如何像魔术一样自动化 shell 脚本

2023-10-23

在上一篇文章中,我们讨论了写作实用的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 命令的一些最重要的方面,以及如何使用它以更智能的方式自动执行任务。

谢谢。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Expect 命令以及如何像魔术一样自动化 shell 脚本 的相关文章

  • CMake:不要为链接中使用的单个库设置 rpath

    我想要做的是配置我的 CMakeLists 文件 以便在构建我的项目时 链接器使用驻留在我的构建树中的共享库 so 的副本来链接可执行文件 但不会在中设置 rpath链接的可执行文件 以便系统必须在加载程序请求时提供该库 具体来说 我想在构
  • “排序文件名 | uniq”不适用于大文件

    我可以从小文本文件中删除重复条目 但不能从大文本文件中删除重复条目 我有一个 4MB 的文件 文件的开头如下所示 aa aah aahed aahed aahing aahing aahs aahs aal aalii aalii aali
  • 如果specfile中的某些条件不满足,如何中止rpm包的安装?

    还有一些事情Requires标签不满足 所以我写了一个脚本来验证这些东西 但是我把它们放在哪里呢 如果没有找到 那么我想退出安装 提示用户在尝试再次安装此 rpm 之前执行这些步骤 writing exit 1 in installtag
  • 使用 AWK 或 SED 以及以下标签以逗号分隔

    使用 AWK 或 SED 以及下面使用的标签以逗号分隔 BEGIN AccountID BEGIN CallerID BEGIN Billed Account Attributes 1111111 1111111 1111111 END B
  • 启动jetty服务器时出现NoClassDefFoundError

    我正在尝试在码头服务器中托管我的网络应用程序 spring 我将 war 文件复制到 jetty 服务器中的 webapp 文件夹中 我并不是想嵌入jetty服务器 而是试图在jetty内托管应用程序 如tomcat 我没有安装jetty
  • Bash 变量:区分大小写?

    Bash shell 脚本区分大小写吗 是可变的date与DATE 是的 它区分大小写 就像 UNIX 的其余部分一样 date and DATE是两个不同的变量 makefile and Makefile是两个不同的文件 h and H是
  • POSIX:FreeBSD 与 Linux 中的管道系统调用

    在 Linux 2 6 35 22 generic 中 man pipe指出 pipeline 创建一个管道 一个可用于进程间通信的单向数据通道 在 FreeBSD 6 3 RELEASE p5 中 man pipe指出 pipeline
  • Ubuntu 上的 Docker 无法连接到本地主机,但可以连接到其 IP

    我运行的是 Ubuntu 18 04 uname r 5 3 0 46 generic 我已经安装了docker docker version Docker version 19 03 8 build afacb8b7f0 我有一个简单的
  • 从命令输出中设置 GDB 中的环境变量

    我试图在挑战中利用缓冲区溢出 缓冲区从环境变量中获取其值 在 GDB 中 我知道您可以使用以下命令设置环境变量 set environment username test 但是我需要传递用户名变量特殊字符 所以我需要执行以下操作 set e
  • 如何获取uinput创建的设备的名称(路径)

    我已经成功设置了一个小程序来创建uinput questions tagged uinput我计划使用它来自动测试接收键盘输入事件的应用程序 我已关注both http thiemonge org getting started with
  • 如何在汇编语言中换行打印多个字符串

    我试图在汇编中的不同行上打印多个字符串 但使用我的代码 它只打印最后一个字符串 我对汇编语言非常陌生 所以请耐心等待 section text global start start mov edx len mov edx len1 mov
  • Linux 中如何获取内存修改通知

    在Linux的用户空间程序中 我通过从堆中分配来获取一块内存 然后将指针分发给在其他线程中运行的许多其他组件来使用 当上述内存被修改时我想收到通知 我当然可以开发一个自定义用户空间解决方案 供其他组件在尝试修改内存时使用 我的情况的问题是这
  • 当模式在范围内时使用 sed 打印范围?

    我有一个充满查询的日志文件 我只想查看有错误的查询 日志条目类似于 path to file executing query QUERY SIZE ROWS MSG DURATION 我想打印所有这些东西 但只有当MSG 包含一些有趣的内容
  • 为什么分配大块内存会失败,而重新分配小块内存却不会失败

    这段代码的结果是x指向一块大小为 100GB 的内存 include
  • Web 本地应用程序 Apache:运行 shell 脚本

    我开发了一个 shell 脚本 我想用它创建一个 UI 我决定使用带有本地服务器的 Web 界面 因为我对 HTML PHP 的了解很少 比 QT 或 Java 的了解更多 我只是希望我的 html 可以在我的计算机上运行 shell 脚本
  • 套接字发送并发保证

    如果我在两个进程 或两个线程 之间共享一个套接字 并且在这两个进程中我尝试发送一条阻塞的大消息 大于下划线协议缓冲区 是否可以保证这两个消息将按顺序发送 或者消息可以在内核内部交错吗 我主要对 TCP over IP 行为感兴趣 但了解它是
  • 每当调用 malloc/free 时输出到 stderr

    使用 Linux GCC C 每当调用 malloc free new delete 时 我想向 stderr 记录一些内容 我试图了解库的内存分配 因此我想在运行单元测试时生成此输出 我使用 valgrind 进行内存泄漏检测 但我找不到
  • 无法在 R 中安装插入符号包(在我的 Linux 机器中)

    我在尝试在 R 中安装插入符号包时遇到以下错误 g error tmp Rtmp2Tos7n R INSTALL2e6e30153a74 nloptr nlopt 2 4 2 lib libnlopt cxx a No such file
  • MYSQL插入GB大小的巨大SQL文件

    我正在尝试创建 Wikipedia DB 副本 大约 50GB 但在处理最大的 SQL 文件时遇到问题 我使用 linux split 实用程序将 GB 大小的文件拆分为 300 MB 的块 例如 split d l 50 enwiki 2
  • bash 别名中允许使用哪些字符[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我最近添加了 alias cd alias cd alias cd 到我的 bash aliases 文件 玩弄这个 我注意到在别名时 被

随机推荐

  • RDBMS 与 NoSQL:为您的项目选择正确的数据库

    为项目选择正确的数据库可能是一个关键决策 会极大地影响项目的成功 最流行的两类数据库是关系数据库管理系统 RDBMS 和 NoSQL 数据库 每种都有其优点和缺点 选择最终取决于项目的具体要求 本文将对 RDBMS 和 NoSQL 数据库进
  • 如何在 Linux 上设置 LogMeIn (Hamachi) VPN

    Hamachi 用于使用或设置 VPN 并通过 VPN 网络连接系统 这提供了一种快速 更简单的方法来创建 VPN 网络和连接系统 您可以在 logmein com 上创建免费帐户并创建网络 您可以使用免费帐户在每个网络中添加最多 5 个系
  • Java 技巧:将字符串转换为日期

    在 Java 编程领域 日期和时间操作是一项基本技能 但是 日期通常作为字符串传递 这需要将这些字符串转换为 Date 对象以进行有效操作 在本综合指南中 我们将详细介绍在 Java 中将字符串转换为日期的过程 了解基础知识 表示日期的字符
  • UFW:通用防火墙规则和命令

    防火墙是一种安全系统 它根据预定义的安全规则监视和控制传入和传出的网络流量 它是任何安全网络的重要组成部分 无论是个人计算机还是大型企业网络 Uncomplicated Firewall UFW 是一个用户友好的命令行界面 用于管理 ipt
  • 编辑 crontab 文件的要点

    在系统管理领域 有一种强大的工具可以让您高效地安排任务 crontab 使用 crontab 您可以在指定的日期和时间执行脚本和命令 这使其成为基于 Unix 的系统中非常有用的实用程序 但是 要充分利用其潜力 您需要了解编辑 cronta
  • 如何在 Linux 中创建交换文件

    交换文件是 Linux 操作系统的重要组件 它通过提供额外的虚拟内存来帮助提高性能 它是在系统物理内存 RAM 填满时保留用作虚拟内存的磁盘空间 在 Linux 中创建交换文件有助于防止系统崩溃和不稳定 在本文中 我们将逐步讨论如何在 Li
  • 如何在 phpMyAdmin 中添加多个主机

    phpMyAdmin 默认配置仅允许连接到本地 MySQL 服务器 但是如果我们运行多个数据库服务器 那么如果我们可以从单个 phpMyAdmin 安装中选择需要连接的服务器 那就太好了 本操作指南将帮助您在 phpMyAdmin 中添加多
  • Bash 选择(制作菜单)

    在本教程中 我们将介绍以下基础知识select在 Bash 中构建 The select构造允许您生成菜单 Bash select构造 The select构造从项目列表生成菜单 它的语法几乎与for loop select ITEM in
  • 如何在 CentOS 7 上安装和配置 Redmine

    Redmine 是最流行的开源项目管理和问题跟踪软件工具之一 它是跨平台和跨数据库的 构建在 Ruby on Rails 框架之上 Redmine包括对多个项目 wiki 问题跟踪系统 论坛 日历 电子邮件通知等的支持 在本教程中 我们将介
  • 如何在 Ubuntu 18.04 上部署 Rocket.Chat

    Rocket Chat 是一个开源团队交流平台 是自托管的 Slack 替代品 它使用 Meteor 框架开发 提供各种功能 包括帮助台聊天 文件共享 视频会议 语音消息 API 等 对于想要托管自己的聊天系统的公司和社区来说 Rocket
  • .bashrc 与 .bash_profile

    如果您在命令行上花费大量时间 您很可能想要自定义您的 shell 环境 这可能意味着创建别名 将新目录添加到 PATH 或更改 shell 提示符的外观 您可能遇到过一些教程 其中他们说将您的配置放在 bashrc bash profile
  • 如何在 CentOS 7 上安装和使用 PHP Composer

    Composer是 PHP 的依赖管理器 类似于Node js 的 npm or Python 的点子 Composer 将提取您的项目所依赖的所有必需的 PHP 包并为您管理它们 它用于所有现代 PHP 框架和平台 例如 Laravel
  • 如何在 CentOS 8 上安装 Apache

    Apache HTTP 服务器是世界上使用最广泛的 Web 服务器 它是一个免费 开源 跨平台的HTTP服务器 具有强大的功能 并且可以通过多种模块进行扩展 在本文中 我们将解释如何在 CentOS 8 上安装和管理 Apache Web
  • 如何在 Debian 9 上安装 CouchDB

    CouchDB 是一个开源的容错且无模式的 NoSQL 数据库 由 Apache 软件基金会维护 CouchDB 服务器将其数据存储在命名数据库中 其中包含以下文档JSON结构 每个文档由许多字段和附件组成 字段可以包括文本 数字 列表 布
  • 如何在 CentOS 7 上安装 Visual Studio Code

    视觉工作室代码是微软开发的开源跨平台代码编辑器 它有一个内置的调试支持 嵌入式Git控制 语法突出显示 代码完成 集成终端 代码重构和片段 在 CentOS 计算机上安装 Visual Studio Code 最简单且推荐的方法是启用 VS
  • 如何在 Ubuntu 18.04 上安装 Mono

    Mono 是一个用于开发和运行基于 ECMA ISO 标准的跨平台应用程序的平台 它是 Microsoft NET 框架的免费开源实现 本教程介绍如何在 Ubuntu 18 04 上安装 Mono 先决条件 这些说明假定您以 root 身份
  • Linux中的su命令(切换用户)

    The su 替代或切换用户的缩写 实用程序允许您使用其他用户 默认为 root 用户 的权限运行命令 Using su是在当前登录会话中切换到管理帐户的最简单方法 当不允许 root 用户通过以下方式登录系统时 这尤其方便ssh或使用 G
  • Linux 中的Whereis命令

    whereis是一个命令行实用程序 允许您查找给定命令的二进制文件 源文件和手册页文件的位置 在这篇文章中 我们将向您展示如何使用Linuxwhereis命令 如何使用whereis命令 语法为whereis命令如下 whereis OPT
  • 在 CentOS 8 上使用 Let's Encrypt 保护 Nginx

    Let s Encrypt 是由互联网安全研究小组 ISRG 开发的免费 自动化 开放的证书颁发机构 提供免费的 SSL 证书 Let s Encrypt 颁发的证书受到所有主要浏览器的信任 并且自颁发之日起 90 天内有效 在本教程中 我
  • Expect 命令以及如何像魔术一样自动化 shell 脚本

    在上一篇文章中 我们讨论了写作实用的shell脚本 我们看到了编写 shell 脚本是多么容易 今天我们要讨论一个对 shell 脚本有神奇作用的工具 该工具是期待命令 or 期待脚本语言 Expect 命令或 Expect 脚本语言是一种