Progress bar for shell apps

shot1.png

Downloading a file, backing up your database, or installing a package for your system are all instances of long lived processes that we encounter daily. When such a process takes a long time to finish, it is always nice to give some kind of visual cue to the user.

A nice and space efficient way to achieve the previous is to use a progress bar or a display counter. This tutorial aims to help you create such an output for a console application.

The hardest part in creating such an output is to figure out how to clear the current line in the output and replace it with another. Well, there is a clever trick involved. Instead of using an \n at the end of the string that is printed to stdout, you can use the \r escape value. These two are familiar values but the first jumps to the start of the line and moves one line down, while the second only moves to the beginning of the line and thus rewrites that line when a new output arrives.

Here is a nice little script that will display a progress bar – written in the ruby programming language, but easily translatable to any other.

def print_progress_bar(finished_percent)
  finished = "#" * finished_percent
  empty    = "-" * (100 - finished_percent)

  print "\r[ #{finished}#{empty} ] #{finished_percent}% "
end

(0..100).each do |count|
  print_progress_bar(count)
  sleep 1
end

 Full line progress bars

fullline.png

The above code snippet works great, if your terminal is wider than ±100 columns. Otherwise it just breaks up your lines and looks ugly. On the other hand if your terminal is much wider than 110 columns the output
is again strange because it leaves much of the space unfilled.

Here is a solution. If we execute the tput cols command it will return us the width of the terminal window in column numbers and we can use it to cleverly calculate the length of our progress bar. The improved — tputs using — code snippet follows

def print_progress_bar(finished_percent)
  fixed_space = 9 # for braces and number

  width = `tput cols`.to_f - fixed_space

  finished_count = ((finished_percent*width)/100).ceil
  empty_count    = width - finished_count

  finished = "#" * finished_count
  empty    = "-" * empty_count

  print "\r[ #{finished}#{empty} ] #{finished_percent}% "
end

(0..100).each do |count|
  print_progress_bar(count)
  sleep 1
end
 
13
Kudos
 
13
Kudos

Now read this

Thor - Awesome CLI apps

Ever wanted to create an awesome command line application but was lost in the sea of options parsing? Well, if you did, and even if you didn’t, Thor is here to help you. But what is Thor exactly? It is a powerful toolkit for writing... Continue →