Запобігайте морганню тексту / екрану, коли ви робите чіткий


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

Відповіді:


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можливості вашого терміналу для друку з поточного місця до кінця екрана.

Якщо ви хочете обробити змінний екран, ви можете перемістити завдання у зовнішній цикл 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запитує поточний розмір екрану в системі.

Подальше читання:


1
Для тих, хто використовує #!/bin/bashта бажає використовувати watchitвбудований в невеликий автономний сценарій з деякими функціями, ви можете це зробити export -f function_name; watchit function_name.
сукупність1166877

Для мене це спрацювало ідеально, за винятком того, що я стикався з кумедними проблемами у верхній частині екрана, де все зміщуватиметься та стає блискучим для довших фрагментів тексту (все скорочується 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

Працював як шарм. Ніякого мерехтіння :)
Ларс Жуель Дженсен

1
Решта мерехтіння можна усунути, включивши clearв буфер, тобто output=$(clear; do_a_lot_of_output_here).
kdb

@kdb Приємна пропозиція! Це майже повністю усуває мерехтіння для мене і набагато простіше, ніж прийнята відповідь.
Майкл Міор

Це працює як шарм! Спочатку я пропустив подвійні лапки в "ехо" $ 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з тими ж результатами (
моргаючи

До сценарію я додав пару рядків, щоб приховати курсор.

Ні курсору - ні стрибків. Але про артефакти? Вихід має випадкову кількість рядків. Чи потрібно мені заповнити весь сценарій пробілами перед початком нового виводу? Але в будь-якому випадку, дякую за ваш час та зусилля: +1 від мене за це, але це не вирішує мою проблему
ravnur

Я знайшов тільки один спосіб позбутися від усіх артефактів: tput ed. Але це спричиняє моргання
ravnur

Який термінальний емулятор ви використовуєте? З tput edправої до do_a_lot...лінії, я бачу миготливий в urxvt , але не XTerm або ст.

1

Як розширення відповіді Крістіана, я зробив наступну функцію 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, що постійно оновляється.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.