I've done such tricks in the build system of an embedded Linux distro. In my case, it was a little different. The build script restricted the scrolling region (via VT100 escape sequences) so that the log was shown in the top N-4 lines of the terminal. The bottom four lines were turned into a static area that was updated with the build progress: what is currently building, percentage progress, and such.
A way achieve what you're looking for is this:
- Move the cursor to the bottom row of the terminal.
- Print ten blank lines to scroll away any existing material.
- Set the scrolling region to the bottom ten lines.
- Run the command.
- Reset the scrolling region.
The escape sequences can be found in numerous references.
The following is something I just banged up. It works with bash on an Ubuntu VM I have here. It relies on $(( ... ))
arithmetic, and stty
supporting -g
to save tty settings in a serialized string. I avoided using \e
in printf
to denote the escape character, which would make this less portable.
We interrogate the number of lines from the terminal because the LINES
variable might not be exported. (We could instead parse out the rows
parameter from the output of stty -a
; then we could avoid the whole dance of putting the tty in raw mode, and obtaining the terminal emulator's response using dd
. On the other hand, this method works even if the rows
value from the tty driver is incorrect.)
Save this script as, say last10
, make it executable and then try for instance last10 find /etc
.
#!/bin/bash
# save tty settings
saved_stty=$(stty -g)
restore()
{
stty $saved_stty
# reset scrolling region
printf "\033[1;${rows}r"
# move to bottom of display
printf "\033[999;1H"
}
trap restore int term exit
# move to bottom of display
printf "\033[999;1H"
printf "\n\n\n\n\n\n\n\n\n\n"
# Query the actual cursor position
printf "\033[6n"
# read tty response
tty_response=
stty raw isig -echo
while true; do
char=$(dd bs=1 count=1 2> /dev/null)
if [ "$char" = "R" ] ; then
break;
fi
tty_response="$tty_response$char"
done
stty $saved_stty
# parse tty_response
get_size()
{
cols=$3
rows=$2
}
save_IFS=$IFS
IFS='[;R'
get_size $tty_response
IFS=$save_IFS
# set scrolling region to 10 lines
printf "\033[$((rows-9));${rows}r"
# move to bottom of display
printf "\033[999;1H"
# run command
"$@"
stderr
?stderr
is not important ;)rsync -av /src /dest | tail -n10
. The-f
switch is to follow for usage in logfile type scenarios;stdout
from anrsync
is finite and the-f
may be tripping you up here.command > /tmp/scratch & while kill -0 $!; do clear; tail -n10 /tmp/scratch; sleep 0.25; done; rm /tmp/scratch
might do the trick.