终端滚动后tput ed命令失效,如何修复交互式Bash脚本问题?
问题描述
我正在编写一个交互式Bash脚本,需要持续编辑自身输出,示例代码如下:
tput sc # 存储光标位置 while true; do tput rc # 恢复光标位置 tput ed # 删除从光标位置到屏幕末尾的所有内容 seq 10 # 输出内容 sleep 1 # 间隔一段时间重复执行 done
预期效果是屏幕上始终只显示一次seq 10的输出,不断被擦除重写。在全新终端中运行时正常,但当终端已有足够多内容出现滚动条后,该功能失效,seq 10的输出会重复显示,如同执行以下代码:
while true; do seq 10 sleep 1 done
此问题在Windows Terminal和MinTTY中均会出现。
补充:stty -a输出如下:
speed 38400 baud; rows 43; columns 171; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = ^Z; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0; -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -tostop echoctl echoke -flusho
解决办法
问题根源在于初始用tput sc存储的光标位置,在终端出现滚动条后已经被移出当前可见屏幕区域。后续tput rc回到这个位置后,tput ed只会删除该位置到终端缓冲区末尾的内容,而当前可见屏幕的内容不会被清除,导致新的输出不断追加,出现重复显示的情况。
可以通过以下两种方式修复:
方法一:每次循环将光标移至屏幕顶部后再擦除
放弃依赖初始存储的光标位置,每次循环都主动将光标移到当前可见屏幕的左上角,再执行擦除操作:
while true; do tput home # 移动光标到屏幕左上角(等价于 tput cup 0 0) tput ed # 删除从光标到屏幕末尾的内容 seq 10 # 输出内容 sleep 1 done
方法二:使用ANSI转义序列直接控制光标与擦除
如果tput命令在某些环境下有兼容性问题,也可以直接用ANSI转义序列实现相同效果:
while true; do printf '\033[H\033[J' # \033[H 移到屏幕左上角,\033[J 删除光标到末尾的内容 seq 10 sleep 1 done
这两种方法都能确保每次循环时,当前可见屏幕的内容被正确清除,再输出最新内容,即使终端出现滚动条也能正常工作。
内容的提问来源于stack exchange,提问作者Verpous
相关产品推荐
相关产品推荐

