为何Expect的puts -nonewline不输出空字符?能否使其与Tcl行为一致?
问题描述
有一个名为PrintNull.tcl的脚本,内容如下:
puts -nonewline "\0\0\0\0"
使用tclsh运行该脚本时,会正常输出四个空字符,通过xxd验证的结果:
tclsh PrintNull.tcl | xxd 00000000: 0000 0000
但使用expect运行时,却没有任何输出:
expect -f PrintNull.tcl | xxd # 无任何输出
奇怪的是,如果移除-nonewline参数,tclsh和expect的行为就一致了,只是都会额外输出一个换行符:
expect -f PrintNull.tcl | xxd 00000000: 0000 0000 0a ..... tclsh PrintNull.tcl | xxd 00000000: 0000 0000 0a .....
请问该行为的原因是什么?能否让Expect处理puts命令时与Tcl表现一致?
原因分析与解决方案
原因
核心差异在于标准输出的缓冲策略:
tclsh默认对标准输出采用行缓冲模式,当输出包含换行符时会立即刷新缓冲区;即使使用-nonewline,脚本运行结束时也会自动刷新缓冲区,所以空字符能正常输出。expect为适配交互式场景(比如控制终端设备、匹配输出内容),默认将标准输出设置为全缓冲模式,且不会在脚本结束时自动刷新无换行的输出内容。当使用puts -nonewline输出空字符时,内容被留在缓冲区中,没有写入到标准输出,因此xxd看不到任何结果;而移除-nonewline后,输出末尾的换行符会触发缓冲刷新,内容才会被输出。
让Expect与Tcl表现一致的方法
可以通过以下两种方式调整Expect的输出行为:
手动刷新缓冲区
在puts命令后显式调用flush命令强制刷新标准输出:puts -nonewline "\0\0\0\0" flush stdout这样即使没有换行符,缓冲区的内容也会被立即输出。
修改输出缓冲模式
在脚本开头设置标准输出为行缓冲模式,和tclsh保持一致:fconfigure stdout -buffering line puts -nonewline "\0\0\0\0"之后所有的
puts操作都会遵循行缓冲规则,遇到换行符自动刷新,脚本结束时也会自动刷新剩余内容。
内容的提问来源于stack exchange,提问作者merlin2011
相关产品推荐
相关产品推荐

