Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show persistent status message on console

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...
like image 920
Caleb Xu Avatar asked Feb 03 '14 22:02

Caleb Xu


2 Answers

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...

like image 69
Lindsay Winkler Avatar answered Oct 28 '22 05:10

Lindsay Winkler


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:

Screenshot

Again, while it does involve installing screen, it is a commonly available tool, and using it for this purpose is exceedingly easy.

like image 33
Adaline Simonian Avatar answered Oct 28 '22 03:10

Adaline Simonian