清除时防止文字/屏幕闪烁


11

我的脚本做类似:

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只用。


您可以添加您的输出clear | hexdump -C吗?
ott--

我扩大了问题。
ravnur

我在stackoverflow.com/questions/5367068/上找到了另一个解决方案- echo -en "\ec"闪存也可以吗?
ott--

我也找到了这个。答案的两个变体也会闪烁。
ravnur

我使用此工具取得了成功:extra.org/article/2009/07/watch1-bash-unicode
Raine 2015年

Answers:


8

发生闪烁是因为脚本清除了整个屏幕。如果它覆盖现有文本并仅在必要时清除,则不会闪烁。

这是一个例子:

#!/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终端的功能从当前位置打印到屏幕末端。

如果你想处理一个可调整大小的屏幕,你可以在任务移动到ROWSCOLS外环内,例如,

#!/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要求系统提供当前的屏幕尺寸。

进一步阅读:


1
对于那些#!/bin/bash希望并希望使用watchit带有某些功能的小型独立脚本的人,可以这样做export -f function_name; watchit function_name
int1166877'6

这对我来说非常有效,除了我在屏幕顶部遇到了有趣的问题之外,在那儿事情会发生变化,并会出现较长的文本块(任何被缩短的地方head)。似乎问题是在计算行数时出现了一次错误(至少在我的设置中-拆分窗格中的ssh会话,iTerm2)。ROWS=`expr $(tput lines) - 1`完美地解决了这个问题。
ohruunuruus

太好了,非常感谢@ thomas-dickey。
mbarkhau

9

一种防止闪烁的方法是在清除屏幕之前获取所有输出,以使清除和重绘之间的时间最短。这类似于双重缓冲的概念:

while :; do
   output=$(do_a_lot_of_output_here)
   clear
   echo "$output"
   sleep 1
done

这不能完全消除闪烁,但是根据我的经验,它的发生频率明显降低。


就像在任何其他情况下一样,双重缓冲可以确保这一天的安全:-)
Ikke 2015年

像魅力一样工作。完全没有闪烁:)
拉尔斯·朱尔·延森

1
剩余的闪烁可以通过包括被消除clear到缓冲器,即output=$(clear; do_a_lot_of_output_here)
kdb

@kdb不错的建议!这几乎为我消除了闪烁,并且比接受的答案要简单得多。
Michael Mior

这就像一个魅力!起初,我错过了'echo“ $ output”'中的双引号,然后所有行都变得混乱了。(所有空格都视为单个空格。)
弹出

5

每次循环时,闪烁都是不可避免的清除屏幕的结果。您可以将光标移到屏幕顶部,然后覆盖旧输出的一部分。

# 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测试过。


在这种情况下,光标开始从随机位置(当然还有伪像)跳到输出的末尾。我也尝试tput clear了相同的结果(闪烁)
ravnur 2013年

我在脚本中添加了几行以隐藏光标。

没有光标-没有跳跃。但是关于文物呢?输出具有随机的行数。开始新输出之前,我是否需要用空格填充所有脚本?但是,无论如何,感谢您的时间和精力:为此,我向+1了,但并不能解决我的问题
ravnur 2013年

我发现只有一种方法可以消除所有工件:tput ed。但这会引起眨眼
ravnur

您正在使用哪种终端仿真器?随着tput ed该右侧前do_a_lot...行,我看到闪烁的urxvt但不是xterm或ST。

1

作为Cristian答案的扩展,我制作了以下bash函数,如果控制台窗口小于命令的输出,则该函数可以工作:

function watcher()
{
    lines=$(tput lines)
    while true; do
        output="$($@ | head -n $lines)"
        clear
        echo -e "$output"
        sleep 2
    done
}

这使您可以将任何命令传递给观察者。如果您使用的是git,请使用git config --global color.status always然后:

watcher git status

将显示始终更新的git status输出。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.