I'm working on a Bash script for massive USB flash memory testing (using f3 under the hood). I need to display a table-like interface with multiple columns and cells.

Currently I'm using printf with and it looks like this:

enter image description here

I have a separate function running for each drive that write out text to a log file. These log files are parsed to display the information to the user.

As you can see some rows have offsets that shouldn't be there but I can't get rid of them It doesn't seem to be caused by long strings being printed. I don't know what's this.

Another problems I have is the refresh time and the need to manually clear and redraw the whole screen at times, due to ocasional stderr messages appearing there from grep or cat when some files don't read properly.

I'm currently doing a partial rewrite of this script and I what I could od better in regard to printing out the data on the screen. I thought about looking into ncurses but that seems like a bit too complicated thing and would probably make things way to complex for me to maintain.

I wonder if there is a way for me to dump the echo or print commands to a text file and then execute that all at once to basically have a text "backbuffer" so my refresh can be more consistent and faster?

I would also want to be able to listen for user's keystrokes and react to that in the background but that's not a priority.

Maybe there's a better way to do this kind of thing in Bash, that I don't know of?

  • 2
    Have you tried ncurses? – NarūnasK Nov 29 '17 at 12:06
  • I haven't tried it, but I wondered if maybe there's a simpler way that wouldn't require me to learn it. – unfa Nov 29 '17 at 12:21
  • Possibly there are some TABs or other characters that have a display width other than 1, or multi-byte characters in your data. See also Why is printf "shrinking" umlaut? – Stéphane Chazelas Nov 29 '17 at 14:08
  • 2
    "due to ocasional stderr messages appearing there from grep or cat". You can redirect errors to /dev/null so that they don't clutter the display. – roaima Jul 13 '19 at 10:23
  • ncurses is designed to help you with such a task, so it surely won't make maintainance more complex then rebuilding the functionality with basic tools. – Philippos Jul 18 '19 at 12:31

You could use tput to move the cursor around, for example tput cup 0 0; echo test will put write "test" to the top left of the screen.

Alternatively, if you wanted to use a buffered approach, you could dump lines to a file, clear the screen and cat the file:

# In program setup
TEMPFILE=$(mktemp) # Create temporary file
trap "rm -f $TEMPFILE" EXIT # Remove temporary on exit

# Main lopp
while true
  echo "TEST" >$TEMPFILE # Clear file and set first line with >
  date >>$TEMPFILE # Append lines to file with >>

  clear # Clear the screen
  cat $TEMPFILE # Dump the file
  sleep 1 # Just for testing to avoid high CPU

Comment out the trap line if you want to leave the temporary file behind for debugging.

|improve this answer|||||

I think you have nearly achieved what you set out to do, albeit with a few minor bugs and possibly some performance problems. Personally, I would first try to solve the bugs, then try to understand where the performance could be improved. However regarding your refresh rate, even programs like top or watch usually run with a refresh every 2 or 1 seconds and this is usually sufficient. You don't say, what rate you are trying to achieve.

There is a similar Stackexchange question, which has two answers/suggestions,

  1. Use the program dialog which is something else to learn.
  2. Shows the creation of bash functions, to clear, reset, write text at a position on the screen, which is a similar set of functions that you would probably use in ncurses, but has the advantage of using echo (a bash built in function) so it doesn't bear the overhead of running /usr/bin/printf to format the output.

Taking your problems in turn.

  1. errors being printed from background commands. Redirect, stderr either to /dev/null if you just want to discard it or to a file for later processing.

  2. Columns bug, show your code, input data nd required output, then we can make suggestions. This bug might be an affect of bug #1, so solve #1 first then address this if it still exists.

  3. Performance, (edit your question) and add your code so that we can see what you are doing and make suggestions.

The other way is to use a different script interpreter, there are so many which to choose depends on which ones you are familiar with. (awk, python, perl, other shells, ...). However if you were not going to use ncurses, the principle would be similar to the bash function definitions shown in the 2nd answer above.

|improve this answer|||||
  • 1
    I would tend to agree that this is a bug issue. My biggest concern is that OP has ".... a separate function for each ....". I hope OP means ".... an instance of the same function for each......". Assuming the latter then the usb() function just needs to standardise what is written to the log file (fixed width/delimited etc) and most of the issues should be sorted. Personally I would also write the usb states to a 'model' and then draw the screen with a 'view' a la MVC. Easy maintenance. – bu5hman Nov 29 '17 at 14:29

Using column -t should work for you.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.