为了配置嵌入式设备(即将映像写入闪存),必须在启动阶段输入一系列众所周知的命令。该算法类似于:
- 在启动期间输入任意键捕获引导加载程序 shell
- 闪光图像A
- 闪光图像B
- ...
- 继续启动(使用新映像)
由于我们必须首先在启动过程中的某个时刻捕获引导加载程序 shell,我认为应用expect
脚本可以很好地解决这个问题。我还想要混合一些其他的 bash 命令来实现关于连接到哪个设备节点等的逻辑。我想到的是(仅预期部分)如下:
#!/bin/bash
DEVICE=...
FLASH_CMD_A=...
#Other bash stuff
expect <<SCRIPT
set timeout 5
spawn plink -serial -sercfg 115200,8,n,1 $DEVICE
expect "Hit any key to stop autoboot"
sleep 1
send "\r"
expect "=>"
sleep 1
send "$FLASH_CMD_A\n"
interact
SCRIPT
echo "Done!"
我观察到的是:第一条期望行被正确捕获,睡眠正在工作,并且换行符似乎正在被发送。下一个期望(捕获提示)及其相应的睡眠似乎也正在工作。发送命令($FLASH_CMD_A)被打印到终端,单词之间有很多空格,但它似乎也有效。
最大的问题是他们interact
似乎没有做任何事情。一旦执行第二个期望/发送,我就会回到 bash shell,甚至从未见过“完成!”打印到标准输出。我还尝试了交互语法:
interact {
"=>"{
send "\r"
exp_continue
}
}
但这没有用根本不。提示从未被捕获,脚本立即退出,就好像该interact
语句根本不存在一样。关于我可能做错了什么有什么想法吗?我有:
expect -v
expect version 5.45
虽然命令似乎我无法确定是否会传递到设备。一旦我返回到 bash shell,设备遵循这些命令的所有输出都会丢失。但是,如果我第二次运行脚本,expect 似乎会转储其文本缓冲区(expect_out
?)并立即退出。有趣的是,我期望之前发送的命令的输出包含在这个缓冲区转储中。
顺便说一句:我在虚拟机环境中尝试了相同的脚本,但没有捕获任何“预期”语句;所有输入都被打印到标准输出并通过。
答案1
作为解决方法,从文件运行 Expect 脚本,而不是通过标准输入:
#!/bin/sh
BLAH='echo hi'
ESCRIPT=`mktemp runner.XXXXXXXXXX` || exit 1
# nope
#expect -d - <<SCRIPT
cat >$ESCRIPT <<SCRIPT
set timeout 5
spawn $SHELL
# FIXME whatever your prompt looks like
expect -ex "% "
send -raw "\r"
expect -ex "% "
send -- "$BLAH\n"
expect -ex "% "
interact
SCRIPT
expect -d $ESCRIPT
echo alas poor $SHELL I knew him well a man of infinit
# and probably also `trap` in the event this code gets whapped with an INT
# or something...
rm $ESCRIPT