Prevent text/screen blinking when doing clear
One way to help prevent flashing is to get all the output before clearing the screen so that there is a minimum amount of time between clearing and redrawing it. This is similar to the concept of double buffering:
while :; do
output=$(do_a_lot_of_output_here)
clear
echo "$output"
sleep 1
done
This does not completely eliminate the flicker, but it happens significantly less frequently in my experience.
The flashing occurs because the script clears the entire screen. If it paints over the existing text and clears only as necessary, then there will be no flickering.
Here is an example:
#!/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
It does this:
- prints the output from the given command that will fit on the screen (no wrapping or scrolling)
- writes over existing lines, clearing the portion of each line which is not overwritten
- uses the
ed
capability of your terminal to print from the current location to the end of the screen.
If you wanted to handle a resizable screen, you could move the assignments to ROWS
and COLS
inside the outer loop, e.g.,
#!/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
because tput
asks for the current screensize from the system.
Further reading:
terminfo
- terminal capability data basetput
,reset
- initialize a terminal or query terminfo database
The flashing is an unavoidable result of clearing the screen each time around the loop. You can move the cursor to the top of the screen and overwrite parts of your old output instead.
# 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
This script will leave artifacts if your output shrinks. It's also not very likely to be portable. I've only tested it with urxvt, xterm, and st.