How To: Progress Bar in Bash

How to add a progress bar to a shell script?

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).

How to: Progress bar in bash

Let's use echo -n '...' $'\r' to print a carriage return:

for ((k = 0; k <= 10 ; k++))
do
echo -n "[ "
for ((i = 0 ; i <= k; i++)); do echo -n "###"; done
for ((j = i ; j <= 10 ; j++)); do echo -n " "; done
v=$((k * 10))
echo -n " ] "
echo -n "$v %" $'\r'
sleep 0.05
done
echo

It makes the cursor move to the beginning of the line to keep printing.

Output is as follows, always in the same line:

[ ##################                ] 50 % 

.../...

[ ################################# ] 100 %

How to add progress bar to shell scripts

So basically its will be a little hack because you have no way to check the real progress of you starting process. Its more state between off/on. But if you still want to make the progress bar this code can do the job:

#!/bin/bash

function ProgressBar {
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")
# Progress : [########################################] 100%
printf "\rProgress : [${_fill// /\#}${_empty// /-}] ${_progress}%%"

}

# Proof of concept
work1() {
sleep 10
nc -lp 5001
}
work2() {
sleep 15
nc -lp 6001
}

work1 &
progress=1
while ! nc -z localhost 5001 ; do
ProgressBar ${progress} 100
let progress=progress+1
sleep 0.3
done
ProgressBar 100 100
echo ""
echo "Work 1 done"

work2 &
progress=1
while ! nc -z localhost 6001 ; do
ProgressBar ${progress} 100
let progress=progress+1
sleep 0.3
done
ProgressBar 100 100
echo ""
echo "Work 2 done"

echo "All services started Successfully !!!"

Again its more Microsoft style progress bare here, we passing the job from x to 100 when nc report success. You can adjust the speed sleep 0.x

Shell : How to print progressbar

I guess counter=$counter+1 does not do what you expect. It just concatenates $counter and "+1". So after n iterations you'll have some sting like "1+1+...+1" (n+1-times). You have that in the expression you pipe to bc and operator precedence (* before +) then leads to the unexpected results.

Change counter=$counter+1 to also use bc as you've done above, thus counter=$(echo "${counter}+1" | bc).

Or change percent_done=$(echo "${counter}*100/${1}" | bc -l ) to percent_done=$(echo "(${counter})*100/${1}" | bc -l ) (note the parenthesis) to overrule operator precedence, if for some reason you really want such a "1+1..+1" string.

How to add Progress bar for shell scripts having few commands?

many solutions the easiest way is using externat commands like pv

du -h /var | tail -2 | pv 

a nicer way can be using functions in your script for the bar display :

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

or even better using the rolling spin :

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

you launch the task as background & bars and/or spin as foreground
of course you make conditions or traps on signals to stop it at end of task/command.

How to add a progress bar to a shell script?

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).

Using Bash to display a progress indicator

In this example using SCP, I'm demonstrating how to grab the process id (pid) and then do something while that process is running.

This displays a simple spinnng icon.

/usr/bin/scp me@website.com:file somewhere 2>/dev/null &
pid=$! # Process Id of the previous running command

spin[0]="-"
spin[1]="\\"
spin[2]="|"
spin[3]="/"

echo -n "[copying] ${spin[0]}"
while [ kill -0 $pid ]
do
for i in "${spin[@]}"
do
echo -ne "\b$i"
sleep 0.1
done
done

William Pursell's solution

/usr/bin/scp me@website.com:file somewhere 2>/dev/null &
pid=$! # Process Id of the previous running command

spin='-\|/'

i=0
while kill -0 $pid 2>/dev/null
do
i=$(( (i+1) %4 ))
printf "\r${spin:$i:1}"
sleep .1
done


Related Topics



Leave a reply



Submit