Reputation: 9342
I'm working on a script that is meant to check a certain status, output the result, sleep for a short time and then start everything over again. The output consists of multiple lines and I want the script to update the output that means to print on the same lines again. It's supposed to work on Mac and Linux. This is what I have so far:
#! /usr/bin/perl
use strict;
print `tput sc`; # Store cursor position
my @lines;
while (1) {
@lines = ();
push(@lines, `tput rc`); # Restore cursor position
push(@lines, `tput ed`); # Clear from cursor to end of screen
push(@lines, `dd if=/dev/urandom bs=1 count=1`); # This is just an example
print @lines;
sleep 1;
}
It works fine as long as I'm not calling the script with my cursor at the end of the terminal window. In the latter case the cursor stays at the end of the window after printing so restoring it's original position does effectively nothing and the next output just goes to a new line.
How can I avoid that?
I don't want to call tput clear
or tput init
since that might loose any previous commands and output. I was thinking about scrolling the window so that the prompt is at the top line before I start outputting but that would require the current cursor row and I can't see how to get that with tput
.
Alternatively, I could remember the number of lines that were printed and then move the cursor back using tput rin
. However, that doesn't work when the output is too long and gets broken across two or more terminal lines.
Upvotes: 0
Views: 1760
Reputation: 4104
Generally programs that do this kind of thing either use a fixed location on the screen, or remember how many lines they've output and jump back the appropriate ammount.
It may also be helpful to note that most terminal emulation windows respond to a Clear Screen command by simply scrolling down enough for the window to appear blank. This means that any information previously on screen is still available "up above". Just don't clear the screen with every pass through the while
loop. Starting with a clear/store combo may be just what you need.
Instead of shelling out for your cursor control, you might try to use Curses
or use Term::ANSIScreen
for finer control of your terminal without all those extra processes.
Extra Credit: If you insist on shelling out for cursor control strings, don't spawn tput
commands with every iteration of the loop. Record it's output, and just print it anew for each pass.
Changing your print line to something like print @ANSI_control_strings, @lines;
could have the added advantage that scalar @lines
will be an accurate account of how many lines you may want to jump back if you change from backticks to a piped open.
Upvotes: 3