expect脚本报“command not found”是因为系统未安装expect包;CentOS/RHEL需yum或dnf install expect,Ubuntu/Debian需apt install expect,且脚本首行须为#!/usr/bin/expect -f。

expect 脚本为什么一运行就报 “command not found”
因为 expect 不是 Linux 默认安装的命令。CentOS/RHEL 需先装 expect 包,Ubuntu/Debian 要装 expect 包(不是 expect-dev)。没装就直接写脚本,#!/usr/bin/expect 这行会失败,bash 报 expect: command not found。
实操建议:
- CentOS 7/8:
yum install -y expect或dnf install -y expect - Ubuntu 20.04+:
apt update && apt install -y expect - 检查是否可用:
which expect应输出类似/usr/bin/expect - 脚本首行必须是
#!/usr/bin/expect -f(-f表示从文件读取,避免参数解析错乱)
如何用 expect 自动应答 ssh 密码或 sudo 密码
expect 的核心是匹配输出、触发动作。ssh 登录时提示 password:,sudo 时提示 [sudo] password for,这些字符串必须精确匹配(注意空格和冒号),否则卡住不动。
常见错误现象:脚本卡在 ssh 连接后不输入密码,或输错密码后无限重试。
实操建议:
- 用
exp_internal 1开启调试,看实际收到什么字符(比如有的系统显示Password:,首字母大写) - 匹配要加通配:
expect "*password*"比expect "password:"更鲁棒 - 发送密码后必须跟
expect eof或interact,否则 expect 进程提前退出,ssh 会断连 - 示例片段:
spawn ssh user@192.168.1.100 expect "*password*" send "mypass\r" expect "$ " send "sudo apt update\r" expect "*password*" send "mypass\r" expect eof
expect 和 shell 混用时变量传不进去怎么办
expect 是独立解释器,不能直接读取 bash 变量。写成 send "$PASS\r" 在 expect 脚本里是空的——这是最常踩的坑。
使用场景:你用 bash 封装 expect 脚本,想把密码、IP 等作为参数传入。
实操建议:
- 用
env传参:export PASS="abc"; expect script.exp,然后在脚本里用set pass $env(PASS) - 或者用
argv:bash 调用时写expect script.exp "192.168.1.100" "mypass",expect 脚本里用lindex $argv 0取 IP,lindex $argv 1取密码 - 不要在 expect 脚本里写
#!/usr/bin/expect -f后直接跟 bash 语法,expect 不认识$VAR - 复杂逻辑建议拆开:bash 负责准备参数和调用,expect 只做交互,避免混写
安装类脚本中怎么处理超时、失败重试和非交互命令
自动化部署最怕卡在某个命令不动(比如 apt install 卡在确认页,或下载源慢导致超时),expect 默认没有超时,会一直等下去。
性能与兼容性影响:不用超时控制,脚本可能挂住几小时;用太短的超时(如 1 秒),又容易误判正常输出。
实操建议:
- 全局设超时:
set timeout 30(单位秒),关键步骤前可临时改,如set timeout 120给下载留时间 - 匹配失败要显式处理:
expect { timeout { send_error "apt update timeout\n"; exit 1 } eof { exit 0 } } - 非交互命令(如
systemctl start nginx)别用 expect 包裹,直接用send+expect "$ "即可,避免过度封装 - 安装完成后验证:用
send "which nginx\r"+expect "/usr/sbin/nginx",比单纯等expect eof更可靠
\033[0m)都会干扰匹配。上线前务必在目标镜像里实测,别只在本地终端跑通就认为没问题。


















