expect脚本是专为自动化交互式任务设计的tcl衍生工具,通过spawn启动进程、expect匹配输出、send发送响应、interact接管会话四大命令,补足shell无法处理“等待提示→输入响应”闭环的短板,必须依赖expect和tcl环境,首行需为#!/usr/bin/expect并赋予执行权限。

Expect 脚本是解决 Shell 中交互式命令自动化的标准方案,不是替代 Shell,而是补足它无法处理“等待提示→输入响应”这一闭环的能力。关键不在写得多,而在匹配准、等待稳、退出清。
脚本能跑起来的三个硬条件
缺一不可,否则直接失败或静默退出:
- expect 可执行路径必须存在:运行 which expect 应返回类似 /usr/bin/expect;若无,先装:apt install expect(Debian/Ubuntu)或 yum install expect(RHEL/CentOS)
- Tcl 运行时必须就位:expect 依赖 Tcl,部分精简系统需单独补装 tcl 包,报 can't find package Tcl 就说明缺这个
- 首行解释器 + 执行权限必须正确:必须是 #!/usr/bin/expect(不用 /usr/bin/env expect),且用 chmod +x script.exp 赋予可执行权限
spawn 后匹配不到提示符?别怪正则,先看真实输出
SSH 登录卡住,往往不是密码没发出去,而是还没等到“password:”就停在了主机验证提示上。
- 加 -d 参数调试:expect -d ./login.exp,观察实际捕获的字符流(注意隐藏控制符)
- 用 -re 支持多态匹配,例如:expect -re "(yes/no|password:|.*\$)"
- 远程提示符千变万化,[root@host ~]#、user@host:~$、bash-4.4$ 都可能,别写死 "$ ",改用 expect -re {\$|#|\%}
- 提示符末尾常带空格或制表符,加 .* 更鲁棒,如 expect "password:.*"
send 密码后脚本就退出?因为你没等它准备好
send 只负责“发”,不负责“等”。发完密码立刻 send 命令,但远程 shell 还没加载完毕,命令就被丢弃了。
- 每次 send 后,必须紧跟一个 expect 等待下一条提示,比如 expect "# " 或 expect -re {$|#}
- 回车要用 ,不是 ;send "ls " 才有效,send "ls " 多数终端不认
- 结尾明确收口:expect eof 表示等进程自然结束;想手动接管后续操作,结尾用 interact
- 密码别硬编码,用 set password $env(PASSWD),运行时 PASSWD=xxx ./login.exp
timeout 别设 -1,分阶段设才可靠
全局 set timeout -1 看似省事,实则危险——网络中断或目标宕机时,脚本会无限挂起,CI 流水线卡死,运维排查困难。
- 连接阶段(spawn ssh)设 10~15 秒:set timeout 15
- 登录后执行命令阶段,按操作复杂度设 5~30 秒,避免单条命令超时误判
- 敏感操作(如 reboot、rm -rf)前可临时延长,但务必设上限











