Expect脚本必须用spawn启动子进程才能交互,不可直接注入;每段逻辑前需有且仅一个spawn,匹配提示符须转义正则元字符,send后必须expect响应,生产环境避免依赖ANSI颜色。

Expect 脚本必须显式 spawn 子进程才能交互
Expect 不是直接“注入”到已有进程的,它必须用 spawn 启动目标命令(比如 ssh、ftp、sudo),否则 expect 和 send 都无从作用。常见错误是写成 expect "password:" { send "123
" } 却没 spawn ssh user@host,结果脚本静默退出、毫无反应。
实操建议:
- 每段 Expect 逻辑前必须有且仅有一个
spawn,重复 spawn 会覆盖前一个会话 - 若要复用同一连接做多步操作(如登录后执行多条命令),所有交互需串在同一个
spawn后面 - 调试时加
set timeout 30和exp_internal 1查看匹配过程
匹配提示符要用准确的正则或精确字符串
Expect 默认开启正则匹配,但像 $、[、] 这类字符在 shell 提示符里很常见,不转义就会误判。例如匹配 [user@host ~]$ ,写成 expect "[user@host ~]$ " 才安全;写成 expect "[user@host ~]$ " 会被当作字符集匹配,极大概率超时失败。
实操建议:
- 用
expect -re显式启用正则时,确保转义所有元字符;用expect -exact匹配固定字符串更稳妥 - 生产环境别依赖颜色或 ANSI 序列——终端输出可能不含颜色,导致匹配不到;加
stty -echo或启动时加-o StrictHostKeyChecking=no可减少干扰 - 密码输入后通常没回显,所以
expect "password:"后send立即跟上,不要等额外提示
send 后必须 expect 下一步,否则可能丢指令
send 是异步发数据,不等远端执行完就继续往下走。如果发完 send "ls
" 紧接着 send "exit
",而远程还没返回 ls 结果,exit 就会挤进输出流,造成命令错乱甚至连接中断。
实操建议:
- 每个
send后必须接expect等待明确响应,比如send "ls "; expect "$ " - 用
expect eof收尾比expect timeout更可靠,避免因网络延迟误判 - 对耗时命令(如
apt update),设长 timeout(set timeout 300)并用expect -re "(#|\$) "泛化提示符匹配
嵌入 Shell 脚本时要用 EOF 传递并处理引号嵌套
把 Expect 逻辑塞进 Bash 脚本,最简方式是用 expect 。注意:单引号包裹的 EOF 会禁用 Bash 变量展开,想传变量得改用双引号 EOF,但这时 Expect 内部的 <code>$、 又容易被 Bash 提前解释——比如 send "$PASS
" 会被 Bash 展开为空,或 expect "$ " 中的反斜杠被吃掉。
实操建议:
- 优先用单引号 EOF,变量用
env传入:export PASS="xxx"; expect ,然后 Expect 里用 <code>$env(PASS) - 若必须用双引号 EOF,Expect 中所有
$写成$,所有写成\ - 避免在 Expect 块里写复杂逻辑——提取为独立 .exp 文件更易测试和复用

















