6

I am writing a little script to process folders. The runtime time is quite long so I would like to add a progress bar.

Here is the iteration :

for file in */
do 
    #processing here, dummy code
    sleep 1
done

Having a counter and knowing the number of folders would be a solution. But I am looking for a more generic and a shorter solution...

I hope someone would have an idea. Thank you for your interest,

Julien

Edit :

I get this solution which do what I want, and is really graphical :

#!/bin/bash
n_item=$(find /* -maxdepth 0 | wc -l)
i=0
for file in /*
do
    sleep 1 #process file
    i=$((i+1))
    echo $((100 * i / n_item)) | dialog --gauge "Processing $n_item folders, the current is $file..." 10 70 0
done

However, I will keep fedorqui 's solution which doesn't take all the screen.

Thank you very much for your time

j.flajo
  • 113
  • 1
  • 5
  • you can show an animation, it is relative easy. but for a real "progress bar", my understanding is you need to know how many % of work was done, how many % is still left. this is hard, it depends on the "processing logic". e.g. for a directory with 1million files it could have more % value. with an empty dir, it could have only 0.0001%.. – Kent Sep 27 '13 at 08:51

3 Answers3

6

Based on the results we posted in How to print out to the same line, overriding previous line? I came with this result:

#!/bin/bash

res=$(find /* -maxdepth 0 | wc -l)
echo "found $res results"
i=1

for file in /*
do
    echo -n "["
    for ((j=0; j<i; j++)) ; do echo -n ' '; done
    echo -n '=>'
    for ((j=i; j<$res; j++)) ; do echo -n ' '; done
    echo -n "] $i / $res $file" $'\r'
    ((i++))
    sleep 1
done

Example

$ ./a
found 26 results
[  =>                        ] 2 / 26 /boot 
[                =>          ] 16 / 26 /root
Community
  • 1
  • 1
fedorqui
  • 275,237
  • 103
  • 548
  • 598
4

Based on fedorqui's amazing solution I made a function which works really well with any loop.

function redraw_progress_bar { # int barsize, int base, int i, int top
    local barsize=$1
    local base=$2
    local current=$3
    local top=$4        
    local j=0 
    local progress=$(( ($barsize * ( $current - $base )) / ($top - $base ) )) 
    echo -n "["
    for ((j=0; j < $progress; j++)) ; do echo -n '='; done
    echo -n '=>'
    for ((j=$progress; j < $barsize ; j++)) ; do echo -n ' '; done
    echo -n "] $(( $current )) / $top " $'\r'
}

So you can easily do for loops like

for (( i=4; i<=20 ; i+=2 ))
do
    redraw_progress_bar 50 4 $i 20
    $something $i
done
echo $'\n'
DarioP
  • 5,377
  • 1
  • 33
  • 52
brunch875
  • 859
  • 5
  • 15
3

If you want a graphical progress bar (GTK+), have a look at zenity :

#!/bin/bash
(
    for i in {0..5}
    do
        echo $((i*25))
        echo "#Processing $((i+1))/5"
        sleep 1
    done
) | zenity --progress --width=400 --title="Please wait" --auto-close
Junior Dussouillez
  • 2,327
  • 3
  • 30
  • 39