<<< Back to Tips Index

30 Oct 2015

Progress Bar

Creating a simple Progress Bar for a shell script

Sometimes all we need is a little patience. Or, at least, something to watch while we're waiting. The infamous Progress Bar is an example of such a thing. If your script needs to wait a while, particularly if it needs to wait for a fixed amount of time, this little progress bar may be of help.

For example, you may need to wait for some external process, such as some remote web service, to complete, but you want to give the user something to watch to show that the script has not died.

In this ficticious example, we are waiting for the URL "http://localhost/status" to return "Ready". Other things might be to wait for an entry to appear in DNS, for a virtual machine to complete booting, for a database entry to be created, and so on. This example is nice and simple to test for, though (and quite easy to set up for yourself - just set up a web server with a file "status" in the DocumentRoot).

#!/bin/bash

progress_bar()
{
  local PROG_BAR_MAX=${1:-30}
  local PROG_BAR_DELAY=${2:-1}
  local PROG_BAR_TODO=${3:-"."}
  local PROG_BAR_DONE=${4:-"|"}
  local i

  echo -en "["
  for i in `seq 1 $PROG_BAR_MAX`
  do
    echo -en "$PROG_BAR_TODO"
  done
  # Note: The following line echoes:
  # 1)   "]" (to end the "[...]" bar)
  # 2)   Control-M (aka Carriage Return) (aka Octal \0015)
  # 3)   "[" (to replace the original "[" and put the cursor in the right place)
  #echo -en "]^M["
  echo -en "]\0015["
  for i in `seq 1 $PROG_BAR_MAX`
  do
    echo -en "$PROG_BAR_DONE"
    sleep ${PROG_BAR_DELAY}
  done
  echo
}

while :
do
  curl http://localhost/status 2>/dev/null | grep "Ready" && break
  echo "`date`: System is not ready. Checking again in 10 seconds..."
  progress_bar 10
done
echo "`date`: System is ready."
Download the progressbar.sh script

The progress bar shows a row of dots (".") and gradually replaces them with vertical pipes ("|"):

Progress Bar

When the 10 seconds are up, all 10 vertical pipes are shown, like so:

Progress Bar

You may have noticed that the function takes up to four arguments - we have just called it with "10" as the width of the progress bar. You can also specify how long to sleep between dots, and also what character to use for unused and used time slots. So you can also have this, which will pass the script's arguments to the progress_bar() function:

  progress_bar $@

Here, I have called it a few times with different arguments to show the results...

Progress Bar

The secret of the progress bar is the overwriting of the line: We use ^M (Carriage Return with no Newline) to send the cursor back to the beginning of the line after it's drawn the initial row of dots. This is shown in the hashed out "echo -en "]^M[". To input the special character in vi, type this sequence of keystrokes, without the padding spaces:

  e c h o   - e n " ] CONTROL-V CONTROL-M [ "

The CONTROL-V tells vi that the next character will be a literal, not to be interpreted.

Or - you can do what the downloaded script does, which is to use Octal characters. It's a bit less convenient, but if you just run man ascii, you can get the Octal forms quite easily. Carriage Return is \0015. So you can use: echo -en "]\0015[" - which is easy to copy/paste without losing the essential BACKSPACE character.

Invest in your career. Buy my Shell Scripting Tutorial today:

 

Steve's Bourne / Bash shell scripting tips
Share on Twitter Share on Facebook Share on LinkedIn Share on Identi.ca Share on StumbleUpon