少于 1 分钟阅读 次阅读

Expect 是一个比 sshpass 强大得多、也复杂得多的老牌自动化工具。如果说 sshpass 是一把专门用来开 SSH 密码锁的“特制钥匙”,那么 expect 就是一个可以帮你完成各种复杂对话的“机器人”。

简单来说,Expect 是用来自动化控制和测试交互式程序的工具。它基于 Tcl 脚本语言,核心原理非常直观:它会“盯着”屏幕上的输出(expect),一旦看到特定的关键词出现,就自动“发送”(send)对应的输入,完美模拟人类敲击键盘的过程。

它不仅能用于 SSH,还能用于 telnetftppasswdsu,甚至是任何会弹出提示框要求人工输入的命令行脚本。


Expect 的核心工作原理(四大指令)

编写 expect 脚本通常围绕以下四个核心指令:

  1. spawn:启动一个新进程(例如 spawn ssh user@host)。
  2. expect:等待程序输出特定的字符串或正则表达式(例如等待出现 password:)。
  3. send:向进程发送字符串,模拟人工输入(例如 send "123456\r"\r 代表回车键)。
  4. interact:完成自动交互后,把控制权交还给人类用户(不退出连接,让你继续手动敲命令)。

一个典型的 Expect 登录 SSH 的脚本示例:

#!/usr/bin/expect

# 设定超时时间
set timeout 30

# 启动 SSH 进程
spawn ssh [email protected]

# 核心逻辑:等待输出并做出反应
expect {
    # 如果遇到首次连接指纹确认,自动回复 yes 并继续等待
    "Are you sure you want to continue connecting" { send "yes\r"; exp_continue }
    # 如果遇到密码提示,发送密码
    "password:" { send "mypassword\r" }
}

# 登录成功后,等待出现命令提示符(比如 # 或 $)
expect "*#*"

# 执行一条命令
send "df -h\r"

# 再次等待提示符,然后把控制权交回给用户手动操作
expect "*#*"
interact


sshpassexpect 的核心区别

维度 sshpass expect
功能定位 单一工具:专为 SSH/SCP/SFTP 提供免交互密码。 通用框架:可以自动化任何基于文本的交互式程序。
使用难度 极低:一行命令即可搞定,无需学语法。 较高:需要学习 Tcl 语法,编写多行脚本。
灵活性 无逻辑:它只是暴力地把密码塞给 SSH 进程,如果遇到意外(比如 yes/no 提示、密码过期修改提示),它会直接报错退出。 极高逻辑性:支持 if/else、正则表达式、循环。它可以根据服务器弹出的不同提示,给出不同的回答。
多步交互 不支持:只能处理登录那一下。如果登录后执行的命令还要密码(比如 sudo),它无能为力。 完全支持:登录后可以继续与 sudo 交互,或者执行那些需要一步步按 Y/N 的安装脚本。
语言集成 只能在 Bash 等 Shell 脚本中作为单行命令调用。 本身是独立脚本语言,但也常被 Python (pexpect)、Go、Shell 等语言内嵌调用。

总结:你应该用哪个?

选择 sshpass,如果:

  • 你只需要写一个非常简单的自动化脚本(比如每天用 scp 备份一次文件)。
  • 你的需求仅仅是“绕过 SSH 登录密码”,并且你可以提前用 -o StrictHostKeyChecking=no 解决掉首次连接的指纹确认问题。
  • 你追求快糙猛,不想写额外的复杂脚本。

选择 expect,如果:

  • 你的工作流包含多重交互(例如:SSH 登录机器 A -> 在 A 上跳板登录机器 B -> 执行需要输入密码的 sudo 命令 -> 运行一个需要人工选择 1/2/3 的交互式脚本)。
  • 你需要管理一些老旧的网络设备(交换机、路由器),它们只能用 telnet 登录,sshpass 根本用不上。
  • 你需要更强大的错误处理能力(比如密码错误重试、超时自动断开)。

(注:无论是 sshpass 还是 expect,把密码明文写在脚本里都是不安全的。在现代运维中,对于 Linux 服务器,SSH 密钥对(公私钥)+ Ansible/SaltStack 等自动化工具 才是终极解决方案。)

留下评论