Progress bar for shell apps October 15, 2014 Written by @igor_sarcevic on

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

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

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

Tweet