当前位置: 首页 > news >正文

Expect-自动化交互工具

一、概述

1.1 Expect是什么?

Expect​ 是一个基于 ​Tcl(Tool Command Language)​​ 的免费编程工具,专门用于实现 ​自动化交互式任务。它的核心价值是 ​替代人工手动输入,自动完成需要与终端交互的程序(如SSH登录、密码修改、FTP传输等)的输入响应过程。

典型应用场景​:

  • 自动化SSH/FTP远程连接(免去手动输入密码)

  • 批量修改系统用户密码

  • 网络设备(路由器/交换机)的配置脚本化

  • 与需要交互的命令行工具(如passwdftpmysql等)交互

作者定义​:

由Don Libes在1990年开发,最初定义为“实现自动交互功能的软件套件”,目标是让系统管理员可以通过脚本模拟人工输入,完成原本需要手动操作的交互任务(甚至能实现简单的BBS聊天机器人)。


1.2 为什么需要Expect?

常规Shell脚本(如Bash)虽然支持循环、条件判断等控制流,但 ​无法直接处理需要交互的程序。例如:

  • 当执行passwd tom修改用户密码时,系统会提示输入新密码并验证,这些交互必须通过键盘手动输入。

  • 若需批量修改多个用户的密码,或通过SSH自动登录远程主机执行命令,Shell无法直接完成这类交互。

Expect的解决方案​:

通过监听程序输出的特定提示(如“密码:”“新的密码:”),自动发送对应的输入(如密码字符串),从而实现 ​无人值守的自动化交互


1.3 与SSH免交互的其他方式对比

实现SSH远程操控主机的免交互连接,常见方法包括:

  1. SSH密钥对​(推荐):通过生成公钥/私钥对,将公钥部署到目标主机,实现无密码登录(最安全且无需额外工具)。

  2. sshpass工具​:直接在命令行或脚本中明文传递密码(安全性低,密码可能被ps命令捕获)。

  3. Expect工具​:通过脚本监听SSH的交互提示(如“password:”),自动发送密码(平衡灵活性与安全性,适合复杂交互场景)。


二、环境准备:安装Expect

2.1 检查是否已安装

在Linux系统中,可通过以下命令检查Expect是否已安装:

rpm -q expect  # CentOS/RHEL
# 或
dpkg -l | grep expect  # Ubuntu/Debian

若未安装,会提示“package expect is not installed”。

2.2 安装方法

根据系统类型选择对应命令:

系统类型

安装命令

备注

CentOS/RHEL

yum install -y expect

需root权限

Ubuntu/Debian

apt-get update && apt-get install -y expect

需联网

macOS

brew install expect

需提前安装Homebrew

源码编译

需先安装Tcl 8.6+,再下载Expect源码编译

适用于特殊环境


三、Expect核心工作原理与基础命令

3.1 Expect的基本工作流程

使用Expect脚本时,其核心流程遵循以下步骤:

  1. 启动交互进程​:通过spawn命令启动需要交互的目标程序(如passwdssh)。

  2. 监听预期输出​:通过expect命令等待目标程序输出的特定提示信息(如“密码:”“新的密码:”)。

  3. 发送响应内容​:当匹配到预期提示后,通过send命令向目标程序发送对应的输入(如密码字符串)。

  4. 结束或继续​:进程执行完成后,通过expect eof(等待进程结束)或继续监听其他交互。

关键内置命令​:spawn(启动)、expect(监听)、send(发送)、exp_continue(继续匹配)。


3.2 基础命令详解

(1)spawn:启动交互进程

功能​:启动一个需要与终端交互的程序(如修改密码、SSH连接)。

语法​:

spawn [选项] 命令 [参数]

示例​:

spawn passwd tom      # 启动修改用户tom密码的交互进程
spawn ssh root@192.168.1.100  # 启动SSH连接远程主机的进程
(2)expect:监听预期输出

功能​:等待目标程序输出的特定字符串(提示信息),若匹配则触发后续动作(如发送输入)。

语法​:

expect [选项] "模式1" {动作1} "模式2" {动作2} ... 
# 支持正则表达式(-re)、超时设置(timeout)等

常见用法​:

expect "密码:" { send "123456\r" }  # 匹配“密码:”后发送密码并回车
expect {"新的密码:" { send "abc123\r" }  # 匹配“新的密码:”后发送新密码timeout { puts "等待超时" }      # 超时后执行动作
}

选项说明​:

  • -re:使用正则表达式匹配(如-re {pass.*:}匹配以“pass”开头后跟冒号的字符串)。

  • timeout:设置等待超时时间(单位:秒,默认10秒,可通过set timeout XX全局设置)。

(3)send:发送响应内容

功能​:向当前交互进程发送指定的字符串(模拟用户键盘输入)。

语法​:

send "要发送的内容\r"  # \r表示回车键(必需,模拟按下Enter)

特殊字符​:

  • \r:回车(Enter键)

  • \n:换行

  • \t:制表符

示例​:

send "123456\r"  # 发送密码“123456”并回车
send "ls -l\r"   # 发送命令“ls -l”并执行
(4)exp_continue:继续匹配

功能​:当需要在一个expect块中匹配多个模式时,通过该命令保持监听状态,不退出当前expect块。

典型场景​:处理需要多次输入的情况(如密码不符合要求需重新输入)。

示例​:

expect {"新的密码:" { send "123456\r"      # 发送新密码exp_continue         # 继续监听下一个提示(如“重新输入密码:”)}"重新输入新的密码:" { send "123456\r"      # 发送确认密码}eof                    # 进程结束时退出
}
(5)其他辅助命令
  • send_user​:向标准输出(屏幕)打印信息(类似Shell的echo),用于调试或日志输出。

    send_user "正在修改用户密码...\n"
  • exp_internal 1​:开启内部调试模式,显示详细的匹配过程(调试用,输出到屏幕)。

  • log_file​:记录完整的交互过程到日志文件(用于问题排查)。

    log_file -a /var/log/expect.log  # 追加记录日志

3.3 变量与流程控制

(1)变量定义与使用
  • 普通变量​:通过set定义,通过$变量名puts $变量名引用。

    set username "tom"      # 定义变量
    set password "123456"  
    puts $username          # 输出变量值
    send "$password\r"      # 在send中使用变量
  • 位置参数​:通过lindex $argv获取脚本传递的参数(类似Shell的$1$2)。

    set user [lindex $argv 0]    # 第一个参数(如脚本调用时传入的用户名)
    set pass [lindex $argv 1]    # 第二个参数(密码)
    puts "用户名: $user, 密码: $pass"

    特殊变量​:

    • $argc:脚本接收的参数总个数

    • $argv0:当前脚本的名称

(2)条件判断(if语句)

语法​:

if {条件表达式} {# 条件成立时执行的命令
} elseif {条件} {# 其他条件
} else {# 默认命令
}

示例​:

if {$argc < 2} {send_user "错误:需传入用户名和密码两个参数!\n"exit 1
} else {set user [lindex $argv 0]set pass [lindex $argv 1]
}
(3)循环语句
  • for循环​:

    for {set i 1} {$i <= 5} {incr i} {puts "当前数字: $i"
    }
  • while循环​:

    set i 1
    while {$i <= 3} {puts "循环次数: $i"incr isleep 1
    }

四、完整脚本示例

4.1 案例1:修改用户密码(基础版)

需求​:通过Expect脚本自动修改用户tom的密码为123456(假设原密码不符合要求需多次输入)。

脚本内容(change_pass.exp)​​:

#!/usr/bin/expect
# 自动修改用户密码脚本spawn passwd tom          # 启动修改密码进程
expect {"新的 密码:" { send "123456\r"   # 发送新密码exp_continue      # 继续监听(可能要求确认密码)}"重新输入新的 密码:" { send "123456\r"   # 发送确认密码}"密码:" {             # 部分系统可能先提示原密码(若需原密码则调整)send "oldpass\r"  # 若有原密码要求,替换为实际原密码exp_continue}eof                   # 进程结束时退出
}

使用方法​:

chmod +x change_pass.exp
./change_pass.exp

4.2 案例2:SSH自动登录并执行命令

需求​:自动登录远程主机192.168.1.100,执行ifconfig ens32命令并获取网卡信息。

脚本内容(ssh_auto.exp)​​:

#!/usr/bin/expect
# SSH自动登录并执行命令set host "192.168.1.100"
set user "root"
set pass "123456"spawn ssh $user@$host     # 启动SSH连接
expect {"yes/no" { send "yes\r"      # 首次连接时确认主机密钥exp_continue      # 继续监听密码提示}"password:" { send "$pass\r"    # 发送密码}
}
expect "#"                # 等待出现命令行提示符(如root用户的#)
send "ifconfig ens32\r"   # 发送查看网卡的命令
expect "#"                # 等待命令执行完成
send "exit\r"             # 退出SSH会话
expect eof                # 等待进程结束

使用方法​:

chmod +x ssh_auto.exp
./ssh_auto.exp

五、Shell脚本调用Expect的方法

5.1 方法1:通过expect -c内联执行

在Shell脚本中直接嵌入Expect代码(适合简单场景):

#!/bin/bash
# 批量修改多个用户密码(通过Shell循环调用Expect)for user in tom alice bob; doexpect -c "spawn passwd $userexpect \"新的 密码:\"send \"123456\\r\"expect \"重新输入新的 密码:\"send \"123456\\r\"expect eof"
done

5.2 方法2:通过<<EOF嵌入脚本(推荐)

使用Here Document将Expect脚本嵌入Shell脚本(更清晰且易维护):

#!/bin/bash
# 批量上传文件到远程主机(通过Expect免交互SCP)for ip in 192.168.1.{112..113}; do/usr/bin/expect << EOFset timeout 15spawn scp /local/script.sh root@$ip:/opt/expect {"yes/no" { send "yes\\r"; exp_continue }"password:" { send "123456\\r" }}expect eof
EOF
done

注意事项​:

  • 必须使用/usr/bin/expect的绝对路径(避免环境变量问题)。

  • <<EOFEOF之间的内容需严格符合Expect语法(缩进不影响执行)。


六、生产环境应用案例:批量采集CPU信息

6.1 需求背景

假设有一个脚本cpuinfo.sh,用于统计服务器的CPU核心数、逻辑CPU数、超线程状态等信息。现需将该脚本批量分发到多台主机(如192.168.200.112~113),并自动执行以收集结果。

6.2 实现步骤

步骤1:编写CPU信息统计脚本(cpuinfo.sh)
#!/bin/bash
echo "逻辑CPU总数: $(grep -c '^processor' /proc/cpuinfo)"
echo "物理CPU颗数: $(grep 'physical id' /proc/cpuinfo | sort -u | wc -l)"
echo "每颗物理CPU的核心数: $(grep 'core id' /proc/cpuinfo | sort -u | wc -l)"
echo "每颗物理CPU的逻辑CPU数: $(grep 'siblings' /proc/cpuinfo | sort -u | awk -F: '{print $2}')"
if [ $(grep 'siblings' /proc/cpuinfo | awk -F: '{print $2}' | head -1) -gt $(grep 'core id' /proc/cpuinfo | sort -u | wc -l) ]; thenecho "超线程已启用"
elseecho "超线程未启用"
fi
步骤2:编写Expect脚本实现分发与执行

​(1)分发脚本到远程主机(auto_upload.exp)​

#!/usr/bin/expect
# 自动上传文件到远程主机if { $argc != 3 } {puts "用法: expect auto_upload.exp <本地文件> <目标主机> <远程目录>"exit 1
}
set local_file [lindex $argv 0]
set host [lindex $argv 1]
set remote_dir [lindex $argv 2]
set pass "123456"spawn scp $local_file root@$host:$remote_dir
expect {"yes/no" { send "yes\r"; exp_continue }"password:" { send "$pass\r" }
}
expect eof

​(2)在远程主机执行脚本(auto_run.exp)​

#!/usr/bin/expect
# 自动在远程主机执行命令if { $argc != 2 } {puts "用法: expect auto_run.exp <目标主机> <要执行的命令>"exit 1
}
set host [lindex $argv 0]
set cmd [lindex $argv 1]
set pass "123456"spawn ssh root@$host "$cmd"
expect {"yes/no" { send "yes\r"; exp_continue }"password:" { send "$pass\r" }
}
expect eof

​(3)Shell脚本整合流程(batch_collect.sh)​

#!/bin/bash
# 批量分发并执行CPU信息采集# 1. 分发脚本到所有目标主机
for ip in 192.168.200.112 192.168.200.113; do/usr/bin/expect << EOFset timeout 10spawn scp cpuinfo.sh root@$ip:/opt/expect {"yes/no" { send "yes\\r"; exp_continue }"password:" { send "123456\\r" }}expect eof
EOF
done# 2. 在所有目标主机执行脚本
for ip in 192.168.200.112 192.168.200.113; do/usr/bin/expect << EOFset timeout 20spawn ssh root@$ip "bash /opt/cpuinfo.sh"expect {"password:" { send "123456\\r" }}expect eof
EOF
done

文章转载自:

http://nC8fzTXD.mpLLd.cn
http://8BLEJGpt.mpLLd.cn
http://T7bkevbJ.mpLLd.cn
http://DGOyrSAg.mpLLd.cn
http://hJS5APFM.mpLLd.cn
http://rRCFm3rB.mpLLd.cn
http://CXCB8wxy.mpLLd.cn
http://pqs6Owao.mpLLd.cn
http://FRMTDhx4.mpLLd.cn
http://F7jnS9AQ.mpLLd.cn
http://IqkdigMI.mpLLd.cn
http://Bv9DRQPF.mpLLd.cn
http://a5c8awni.mpLLd.cn
http://XIpDsu22.mpLLd.cn
http://srkwWBAP.mpLLd.cn
http://WPSyaCCp.mpLLd.cn
http://Q7xzZxvW.mpLLd.cn
http://66P4NVWp.mpLLd.cn
http://BCki7t1j.mpLLd.cn
http://O17mveB4.mpLLd.cn
http://uzQZbxtN.mpLLd.cn
http://rthlIDUh.mpLLd.cn
http://CoPRdyia.mpLLd.cn
http://hNxUcR3q.mpLLd.cn
http://K6PAHSb3.mpLLd.cn
http://atSVjLCu.mpLLd.cn
http://Fy5HdOHP.mpLLd.cn
http://PGUGkSI8.mpLLd.cn
http://fOStUVxM.mpLLd.cn
http://ZheUbenx.mpLLd.cn
http://www.dtcms.com/a/375312.html

相关文章:

  • RL【6】:Stochastic Approximation and Stochastic Gradient Descent
  • 计算机毕设Python项目:基于爬虫技术的网络小说数据分析系统
  • 基于springboot 校园餐厅预约点餐微信小程序的设计与实现(代码+数据库+LW)
  • Day20 K8S学习
  • Mockito 原理与实战
  • Django项目架构
  • SpringBoot整合通用ClamAV文件扫描病毒
  • 提权分析报告 —— 基于DriftingBlues: 4靶场
  • 设计模式-原则概述
  • LAMPSecurity: CTF8靶场渗透
  • python网络爬取个人学习指南-(五)
  • CSS 基础概念
  • 在企业内部分发 iOS App 时如何生成并使用 manifest.plist
  • AJAX入门-AJAX 概念和 axios 使用
  • 框架-MyBatis|Plus-1
  • Spring Boot 2.7 启动流程详解
  • springboot框架使用websocket实现一个聊天室的细节
  • Kubernetes集群部署Jenkins指南
  • 027、全球数据库市场深度分析:技术革命下的产业格局重塑
  • 贪心算法与动态规划:数学原理、实现与优化
  • Oracle APEX 利用卡片实现翻转(方法二)
  • 记一次 electron 添加 检测 终端编码,解决终端打印中文乱码问题
  • 从生活照料到精神关怀,七彩喜打造全场景养老服务体系
  • 2025-09-08升级问题记录: 升级SDK从Android11到Android12
  • BizDevOps 是什么?如何建设企业 BizDevOps 体系
  • 一、ARM异常等级及切换
  • 【项目复现】MOOSE-Chem 用于重新发现未见化学科学假说的大型语言模型
  • mybatis plus 使用wrapper输出SQL
  • PgSQL中优化术语HOT详解
  • Python 绘制 2025年 9~11月 P/1999 RO28 (LONEOS) 彗星路径