我的脚本做了类似的事情:
while :;
clear
do_a_lot_of_output_here
sleep 1
done
当我执行清除和输出时,是否有任何选项可以防止屏幕闪烁?我想像在watch
命令中那样执行此操作(但它写在 中C
)。有什么建议吗?
clear | hexdump -C
00000000 1b 5b 48 1b 5b 32 4a |.[H.[2J|
00000007
PS. 我bash
只使用。
答案1
帮助防止闪烁的一种方法是在清除屏幕之前获取所有输出,以便在清除和重绘屏幕之间留出最短的时间。这与双缓冲的概念类似:
while :; do
output=$(do_a_lot_of_output_here)
clear
echo "$output"
sleep 1
done
这并不能完全消除闪烁,但根据我的经验,闪烁发生的频率明显较低。
答案2
发生闪烁是因为脚本清除了整个屏幕。如果它覆盖现有文本并仅在必要时清除,则不会出现闪烁。
这是一个例子:
#!/bin/sh
watchit() {
HOME=$(tput cup 0 0)
ED=$(tput ed)
EL=$(tput el)
ROWS=$(tput lines)
COLS=$(tput cols)
printf '%s%s' "$HOME" "$ED"
while true
do
CMD="$@"
${SHELL:=sh} -c "$CMD" | head -n $ROWS | while IFS= read LINE; do
printf '%-*.*s%s\n' $COLS $COLS "$LINE" "$EL"
done
printf '%s%s' "$ED" "$HOME"
sleep 1
done
}
watchit top -b -n 1
它这样做:
- 打印给定命令的输出,该输出将适合屏幕(不换行或滚动)
- 覆盖现有行,清除每行未被覆盖的部分
- 使用
ed
终端的功能从当前位置打印到屏幕末尾。
如果您想处理可调整大小的屏幕,您可以将分配移动到外部循环内部,例如ROWS
,COLS
#!/bin/sh
watchit() {
HOME=$(tput cup 0 0)
ED=$(tput ed)
EL=$(tput el)
printf '%s%s' "$HOME" "$ED"
while true
do
ROWS=$(tput lines)
COLS=$(tput cols)
CMD="$@"
${SHELL:=sh} -c "$CMD" | head -n $ROWS | while IFS= read LINE; do
printf '%-*.*s%s\n' $COLS $COLS "$LINE" "$EL"
done
printf '%s%s' "$ED" "$HOME"
sleep 1
done
}
watchit top -b -n 1
因为tput
需要从系统获取当前的屏幕尺寸。
进一步阅读:
答案3
闪烁是每次循环清除屏幕时不可避免的结果。您可以将光标移动到屏幕顶部并覆盖旧输出的部分内容。
# You may want to do this if your code is in a script.
unhide_cursor() {
printf '\e[?25h'
}
trap unhide_cursor EXIT
# Hide the cursor (there is probably a much better way to do this)
printf '\e[?25l'
clear
while true ; do
# Move the cursor to the top of the screen but don't clear the screen
printf '\033[;H'
do_a_lot_of_output_here
sleep 1
done
如果您的输出缩小,此脚本将留下工件。它也不太可能便携。我只用 urxvt、xterm 和 st 对其进行了测试。
答案4
取决于你是一根线还是多根线。 tput 不是一个坏选择,但我喜欢使用 esc 代码......
while true
do
printf "^[[H^[[0K$do_a_lot_of_output"
sleep 0.01
done
^[[H将光标移动到 0,0 或左上角,^[[0K 删除从当前光标位置到行尾的内容。
^[[0K很好,因为它将清除从当前光标位置到行尾的行,并且如果下一个字符串恰好比前一个字符串短,则不会看到任何残留数据
一个例子是,如果在第一次迭代期间 $do_a_lot_of_output = 20 ,然后在第二次迭代期间 $do_a_lot_of_output = 5 ,则输出将为 50。如果您不包括 ^[[0K 因为它只会输出它需要的范围, 20 中的 2 被新的 5 覆盖,但 0 仍然会给你一个误导性的 50。
我觉得^[[K也可以用
按 ctrl+v 开始 esc 代码序列,然后按 ESC 生成 ^[,然后添加另一个 [ + 本例中的代码 H 或 K
你把它们放在一起得到 ^[[H 或 ^[[K
Ansi 转义码列表: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797