Pergunta

I want to show a progress bar during a bash operation in a specific format something similar to the following:

[###########](40%)

after update it should become

[###############](50%)

and then similarly reach upto 100%

Is there any way to achieve this

I wrote the following bash program but i don't know how to show the percentage in this on same line:

#!/bin/bash
{
    echo -n "["
    for ((i = 0 ; i <= 100 ; i+=6)); do
        sleep 0.05
        echo -n "###"
    done
    echo -n "]"
    echo
}

Let's assume that a certain number of operations are being performed in a loop and after the completion of each operation, I want to report some progress. I don't want to install pv or any other utilities that does not come with default Ubuntu 12.04 installation.

Foi útil?

Solução

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 % 

Outras dicas

Using printf:

for((i=0;i<=100;i+=6)); do
    printf "%-*s" $((i+1)) '[' | tr ' ' '#'
    printf "%*s%3d%%\r"  $((101-i))  "]" "$i"
    sleep 0.1
done; echo

Output: (in same line.. printed on different lines here for demo.)

[                                                                                                   ]  0%
[######                                                                                             ]  6%
[############                                                                                       ] 12%
[##################                                                                                 ] 18%
[########################                                                                           ] 24%
[##############################                                                                     ] 30%
[####################################                                                               ] 36%
[##########################################                                                         ] 42%
[################################################                                                   ] 48%
[######################################################                                             ] 54%
[############################################################                                       ] 60%
[##################################################################                                 ] 66%
[########################################################################                           ] 72%
[##############################################################################                     ] 78%
[####################################################################################               ] 84%
[##########################################################################################         ] 90%
[################################################################################################   ] 96%

You can use pv as the progress bar:

{
    for ((i = 0 ; i <= 100 ; i+=6)); do
        sleep 0.5 
        echo "B"
    done | pv -c -s 34 > /dev/null
}

There is a lot of options, you may save and restore cursor position like this:

echo -e "\e[s 10 \e[u"
echo -e "\e[s 20 \e[u"

This is one of the vt100 terminal controlling commands, one of the commands in list:

http://www.cse.psu.edu/~kyusun/class/cmpen472/11f/hw/hw7/vt100ansi.htm

or just use \r to move cursor to the beginning of the line and redraw bar each time

echo -e "Original\rOverwrite"

The \r is more portable and will work across most UNIXes (unsure about MacOS)

In your example:

echo -n "["
for ((i = 0 ; i <= 100 ; i+=6)); do
    echo -ne "###\e[s] ($i%)\e[u"
    sleep 0.5
done
echo

I liked the approach with pv but the previous answer on here didn't really mention how one could utilize it to display a specific progress percentage, so I came up with the following

dd if=/dev/urandom count=23 bs=1 2> /dev/null | pv -f -p -w 40 -s 100 > /dev/null

This will display a progress bar with 23%. With dd you can create a file of 23 bytes, pipe it into pv where we specify that the file we expect has a total size of 100.

[======>                           ] 23%

You can do something like below:

#!/bin/bash

func1() {
#reset
str=`printf '%*s' $1 ''|tr ' ' '#'`
echo -n "Loading Module: [ $str ] $1%Complete" $'\r'
#echo $processCounter
}

processCounter=0

while [  $processCounter -lt 100 ]; do

        #After Operation 1
        sleep 2
        let processCounter=processCounter+15
        func1 $processCounter

        #After operation 2
        sleep 2
        let processCounter=processCounter+35
        func1 $processCounter

done

sleep is Just to simulate the time require by application to install.

Using the above syntax You can do as below

#!/bin/bash
{
    #echo -n "["
    for ((i = 0 ; i <= 100 ; i+=6)); do
        sleep 1
        str=`printf '%*s' $i ''|tr ' ' '#'`
        echo -n "[ $str ] $i %Complete" $'\r'
    done
    echo -n "]"
    echo
}

Hope this helps!!

Using tput commands

#!/bin/bash

x=0
load=''

TEST()
{

echo doin stuff


}
tput smcup

while [[ $x -lt 100  ]]; do
        TEST
        load="$load#"



         (( x = x + 1 ))
        echo "loading [" $load "] $x%"
        sleep 0.1
        if [[ $x -eq 100 ]]
        then
                echo done
                read -s LAL
        fi

        tput clear
done
tput clear
tput rmcup

A sed based approach:

for((i=1;i<=100;i++)); do
    printf "[%100s] $i%%\r" | sed -r "
          s/ /#/$i;
          h;
          s/.*#//;
          x;
          s/#.*/#/;
          s/ /#/g;
          G;
          s/\n//";
     sleep 0.1
 done;echo

Explanation:

  1. Print string "[<100 spaces here>] progress number%\r"
  2. Replace i'th space with #
  3. Copy to hold space
  4. Split the string by # & store both parts - one in pattern space & one in hold space.
  5. replace all spaces in first part by #
  6. Join both the strings

https://github.com/extensionsapp/progre.sh

Create 24 percent progress: progreSh 24

enter image description here

My suggestion is not a progress bar, but gives visual feedback of a long running process. It writes a period every one second at the end of a message.

function progress_start ()
{
   # create background process to echo a period every 1 second
   # to give feedback for long running processes
   echo -ne $1; while :; do echo -n .; sleep 1; done &
   progress_pid=$!
}
 
function progress_end ()
{
   echo -e $1;
   # silently kill the background process
   kill $progress_pid && wait $progress_pid &> /dev/null
}

Here is an example of usage.

progress_start 'Process that runs for several seconds'
sleep 7
progress_end '\nProcess complete.'

Result:

$ ./progress
Process that runs for several seconds.......
Process complete.
$
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top