如何将expect操作qemu树莓派时的命令输出保存到宿主机文件?
问题原因
- expect默认会将spawn进程的所有输出同步打印到控制台,所以命令输出直接显示在终端,没有被捕获
gets $ftty仅单次读取一行内容,发送echo命令后第一行读到的是命令本身的输入回显,还没拿到实际的输出内容,写入文件的是空行,所以只有一个换行符- 读取输出的时机早于命令输出返回时间,导致内容读取不完整
修正方案
推荐直接使用expect内置的输出捕获逻辑,实现更稳定:
spawn qemu-system-arm --serial mon:stdio ... # 关闭spawn进程输出到控制台的默认行为 log_user 0 expect { "login:" { send "pi\r" } } expect { "Password:" { send "raspberry\r" } } expect "pi@raspberrypi" set fsignature [open "test.out" w] send "echo 'Hello world!'\r" # 等待命令执行完成返回提示符,匹配区间内的所有输出存在$expect_out(buffer) expect "pi@raspberrypi" # 过滤命令回显、控制字符和提示符,提取实际输出内容 regexp {echo 'Hello world!'\s+(.*?)\s+pi@raspberrypi} $expect_out(buffer) match cmd_output puts $fsignature $cmd_output close $fsignature send "sudo shutdown now\r" wait
如果需要使用exp_open通道方式读取,修改后的代码如下:
spawn qemu-system-arm --serial mon:stdio ... log_user 0 expect { "login:" { send "pi\r" } } expect { "Password:" { send "raspberry\r" } } expect "pi@raspberrypi" set ftty [exp_open -leaveopen] set fsignature [open "test.out" w] send "echo 'Hello world!'\r" expect "pi@raspberrypi" # 读取通道内所有返回内容 set all_output [read $ftty] regexp {echo 'Hello world!'\s+(.*?)\s+pi@raspberrypi} $all_output match cmd_output puts $fsignature $cmd_output close $ftty close $fsignature send "sudo shutdown now\r" wait
关键改动说明
- 新增
log_user 0配置,关闭spawn进程输出到控制台的默认行为,所有输出仅流入expect缓冲区或exp_open打开的通道 - 先等待命令执行完成、提示符返回后再读取输出,避免内容读取不完整
- 通过正则表达式过滤掉命令回显、控制字符和提示符,仅保留需要的命令执行结果
内容的提问来源于stack exchange,提问作者OrangeDog
相关产品推荐
相关产品推荐

