I am working on a program that sends a lot of output to stdout, but I want to be able to easily tell what the program is doing. I've seen some programs show the output of a script or program, yet the last line on the console is "reserved", meaning the output from the commands are shown on the screen, but the last line (or two, or however many) are reserved for a static or occasionally changing status text (e.g. Building <xxxxxx>...
). This way, one can see output from the script/program for debug/troubleshooting purposes, but also quickly glance over and see the status of the program. Is there any way to achieve this with a shell script? I don't mind using built-in system tools, such as awk
, to format the text, as long as the tools used are commonly found on most systems. If possible, I'd also like to avoid ncurses
and other libraries as well.
If you still don't understand what I'm saying, I'll try to illustrate it here:
make -gcc -NOFLAGS -someotherGibberishHere Component1afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component2afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component3afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component4afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component5afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component6afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component7afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component8afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component9afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component10afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component11afdjadfjfadkladfjk . . (etc.) . ------------------------------------------------------------------------ Installing component 11/134...
In this particular example, I'd like for the line "Installing component 11/134..." to remain there even once the console output starts to scroll. Preferably, I'd also like to keep that line right above it too.
That way, once we get into the thick of the program and normally the shell would've started scrolling, we'd still see:
. . (more lines of output here) . make -gcc -NOFLAGS -someotherGibberishHere Component58afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component59afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component60afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component61afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component62afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component63afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component64afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component65afdjadfjfadkladfjk make -gcc -NOFLAGS -someotherGibberishHere Component66afdjadfjfadkladfjk ------------------------------------------------------------------------ Installing component 66/134...
It might be worth having a look into the capabilities of tput
.
Something like the following could form the beginning of a solution to always print the status line at the bottom of the screen:
numlines=$(tput lines)
numcols=$(tput cols)
numcols=$(expr $numcols - 1)
separator_line=$(for i in $(seq 0 $numcols);do printf "%s" "-";done;printf "\n")
tput cup $numlines
echo $separator_line
echo <your status line>
The intention of this logic is to:
work out how many lines on the screen and move to the bottom
work out how many columns and build the separator line to span that many columns
print the separator line and then your status line
Having said that, I feel certain there must be a more elegant way to achieve what you want to do...
While it would require having a client-side dependency, there is a way to do just this with screen
.
#!/bin/bash
# Check if script was started in our screen session
if [ -z "$INTERNAL_INIT_SCRIPT" ]; then
# Create temporary screen config file to avoid conflicts with
# user's .screenrc
screencfg=$(mktemp)
# Show status line at bottom of terminal
echo hardstatus alwayslastline > "$screencfg"
# Start script in a new screen session
INTERNAL_INIT_SCRIPT=1 screen -mq -c "$screencfg" bash -c "$0"
# Store screen return code
ret=$?
# Remove temporary screen config file
rm "$screencfg"
# Exit with the same return code that screen exits with
exit $ret
fi
total=134
function set_status {
screen -X hardstatus string "[$1/$total] $2"
}
# Prints "[1/134] Installing jq..." to the status line
set_status 1 'Installing jq...'
# Install some component
I'm using this in a script I made to initialize Fedora servers I spin up on DigitalOcean. Here's what it looks like in practice:
Again, while it does involve installing screen
, it is a commonly available tool, and using it for this purpose is exceedingly easy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With