向Expect脚本传递密码参数失败,请求问题排查指导
问题描述
我写了一个需要传递密码作为参数的expect脚本:
#!/usr/bin/expect -f set password [lindex $argv 0]; spawn iroot expect ".* password for" sleep 3 send "$password\r" sleep 5 send "dmidecode -t system | grep Manufacturer > /tmp/manufacdetails.txt\r" send "exit\r" interact
尝试用命令./getmanufacdetailsTest.sh password123执行,但脚本无法正常工作,请问哪里操作出错了?
可能的问题及解决方法
这里有几个常见的坑可能导致你的脚本失效,咱们一个个排查:
1. 脚本缺少执行权限
首先检查脚本是否有可执行权限,如果没有的话系统会直接拒绝执行。执行以下命令添加权限:
chmod +x getmanufacdetailsTest.sh
2. 匹配模式不够精准(最可能的原因)
你的expect ".* password for"匹配规则太宽泛,而且大概率和iroot实际输出的密码提示不匹配。比如很多工具的密码提示是类似Password for user:或者直接Password:,这种情况下你的正则匹配根本抓不到目标内容。
建议改成更精准的匹配,或者用正则表达式捕获核心提示,比如:
# 匹配包含"password for"的任意行,兼容末尾带冒号的情况 expect -re "password for.*:"
如果能确定实际的提示文本(比如你手动执行iroot看到的是Enter your password:),直接写死匹配字符串会更可靠:expect "Enter your password:"。
3. 固定sleep不可靠,应该用expect等待而非延迟
用sleep 3和sleep 5是很不稳定的——不同环境下命令执行速度差异很大,可能sleep时间不够导致发送密码时提示还没出现,或者sleep太久完全是浪费时间。
正确的做法是用expect等待下一个预期的系统反馈,比如输入密码后等待root shell的提示符(比如#),再发送后续命令:
send "$password\r" # 等待root shell的提示符,根据你的实际环境调整符号 expect "#" send "dmidecode -t system | grep Manufacturer > /tmp/manufacdetails.txt\r" # 等待命令执行完成后的提示符再退出 expect "#" send "exit\r"
4. 最后用expect eof替代interact更合适
interact是用来让用户和spawn的进程手动交互的,但你已经发送了exit命令,进程应该正常退出,用expect eof等待进程结束更合理,避免脚本莫名卡住:
send "exit\r" expect eof
5. 增加参数校验(可选优化)
可以在脚本开头加个判断,如果用户没传递密码参数就直接提示用法,避免无意义的执行:
if { $argc != 1 } { puts "Usage: $argv0 <password>" exit 1 } set password [lindex $argv 0]
内容的提问来源于stack exchange,提问作者user10711938

