How to add a progress bar to a shell script?


Question

When scripting in bash or any other shell in *NIX, while running a command that will take more than a few seconds, a progress bar is needed.

For example, copying a big file, opening a big tar file.

What ways do you recommend to add progress bars to shell scripts?

1
375
5/30/2012 10:56:14 AM

Accepted Answer

You can implement this by overwriting a line. Use \r to go back to the beginning of the line without writing \n to the terminal.

Write \n when you're done to advance the line.

Use echo -ne to:

  1. not print \n and
  2. to recognize escape sequences like \r.

Here's a demo:

echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'
echo -ne '\n'

In a comment below, puk mentions this "fails" if you start with a long line and then want to write a short line: In this case, you'll need to overwrite the length of the long line (e.g., with spaces).

653
9/6/2018 1:42:01 AM

You may also be interested in how to do a spinner:

Can I do a spinner in Bash?

Sure!

i=1
sp="/-\|"
echo -n ' '
while true
do
    printf "\b${sp:i++%${#sp}:1}"
done

Each time the loop iterates, it displays the next character in the sp string, wrapping around as it reaches the end. (i is the position of the current character to display and ${#sp} is the length of the sp string).

The \b string is replaced by a 'backspace' character. Alternatively, you could play with \r to go back to the beginning of the line.

If you want it to slow down, put a sleep command inside the loop (after the printf).

A POSIX equivalent would be:

sp='/-\|'
printf ' '
while true; do
    printf '\b%.1s' "$sp"
    sp=${sp#?}${sp%???}
done

If you already have a loop which does a lot of work, you can call the following function at the beginning of each iteration to update the spinner:

sp="/-\|"
sc=0
spin() {
   printf "\b${sp:sc++:1}"
   ((sc==${#sp})) && sc=0
}
endspin() {
   printf "\r%s\n" "$@"
}

until work_done; do
   spin
   some_work ...
done
endspin

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon