通过SSH自动获取控制器诊断文件时Expect脚本致文件损坏的问题排查
看起来你的Expect脚本在处理二进制数据和输出转发时出了问题——tar.gz是二进制文件,而Expect默认的文本模式处理会破坏数据结构,再加上log_user的时机设置导致输出丢失或损坏。咱们来拆解问题并修复它:
原脚本的问题所在
- 二进制数据被篡改:Expect原本是为文本交互设计的,当你用
expect和log_user捕获输出时,它可能会修改换行符(比如把\r\n转成\n)或者插入意外字符,直接破坏tar.gz的二进制结构。 - 输出丢失或延迟:一开始设置
log_user 0会屏蔽所有spawn进程的输出,可能在你打开log_user 1之前就错过了tar流的开头部分。即使开启后,Expect的内部处理也会干扰原始二进制流。 - EOF处理不可靠:用
expect eof等待结束并不能保证拿到完整的二进制流——如果传输时间过长或者输出出现停顿,超时机制可能提前触发,导致文件被截断。
适配二进制输出的修复脚本
这个脚本在认证完成后跳过文本解析,直接把原始二进制流转发到标准输出(这样管道输出到diags.tgz就正常了):
#!/usr/bin/expect -f # 关闭Expect内部日志,避免污染二进制输出 exp_internal 0 # 设置足够长的超时时间,适配大体积诊断文件 set timeout 300 # 启动SSH命令获取压缩后的诊断文件 spawn ssh diag@controller tarred # 处理认证流程:匹配密码提示并发送密码 expect { "?assword:" { send "unrealpassword\r" exp_continue } # 捕获认证失败场景,避免脚本挂起 "Permission denied" { puts stderr "错误:认证失败,请检查密码是否正确" exit 1 } # 认证完成后,直接转发原始输出不做任何修改 -re "\r\n" { # -nobuffer 确保无缓冲延迟或文本处理 interact -nobuffer } }
为什么这个脚本有效
exp_internal 0:关闭Expect的调试日志,防止这些日志混入tar.gz文件导致损坏。interact -nobuffer:直接将SSH进程的标准输出无缓冲地转发到脚本的标准输出,完全保留tar.gz的原始二进制结构。- 错误处理:
expect块会捕获认证失败的情况,让你得到明确的错误提示,而不是拿到一个不完整的损坏文件。
额外建议
- 先不管道到文件,直接运行脚本测试认证是否正常:
./get_diags.exp会输出一堆乱码(这是tar.gz二进制的正常表现),说明数据流没问题。 - 如果还是出现超时,增大
set timeout的值——有些诊断文件体积较大,传输需要更长时间。
内容的提问来源于stack exchange,提问作者G. Ryvia
相关产品推荐
相关产品推荐

