Create a progress bar in bash

How can I create an progress bar with bash?

This is my script:

 #!/bin/bash
 pass='number1 number12 number13 number14 number15 number16'
 chk='number14'
 for i in $pass ; do
 if [ "$i" == "$chk" ]; then
 echo ' Found ^_^'
 else
 echo 'loading 50%'
 fi
 done

I want to replace echo 'loading 50%' with anything to create an progress bar.


Solution 1:

whiptail comes preinstalled on Ubuntu and many other distros, and will show full-screen (but still terminal-based) progress elements.

dialog is a superset of whiptail, so this example will work equally well with both. It does provide more advanced UI elements, so it may come in handy if you're looking for user interaction such as file pickers and forms, but it has the disadvantage of not coming preinstalled on many systems.

whiptail

dialog

for i in $(seq 1 100)
do
    sleep 0.1 
    echo $i
done | whiptail --title 'Test script' --gauge 'Running...' 6 60 0

Note that the script output is interpreted as a percentage, so you may have to adjust your output accordingly.

Whiptail and Dialog also allow you to modify the text at run time via a rather cryptic syntax:

phases=( 
    'Locating Jebediah Kerman...'
    'Motivating Kerbals...'
    'Treating Kessler Syndrome...'
    'Recruiting Kerbals...'
)   

for i in $(seq 1 100); do  
    sleep 0.1

    if [ $i -eq 100 ]; then
        echo -e "XXX\n100\nDone!\nXXX"
    elif [ $(($i % 25)) -eq 0 ]; then
        let "phase = $i / 25"
        echo -e "XXX\n$i\n${phases[phase]}\nXXX"
    else
        echo $i
    fi 
done | whiptail --title 'Kerbal Space Program' --gauge "${phases[0]}" 6 60 0

pv shows the progress of a file or stream being piped through it. It cannot however be (easily?) used to show progress of a custom operation such as a loop. It's designed specifically for streams.

$ head -c 1G < /dev/urandom | pv -s 1G > /dev/null
 277MB 0:00:16 [17.4MB/s] [========>                           ] 27% ETA 0:00:43

Some real-world examples where pv comes in handy:

# progress while importing a DB dump
pv mybigfile.sql | mysql -uroot -p dbname

# importing straight from a remote server
ssh user@server 'cat mybigfile.sql.gz' | pv | gzip -cd | mysql -uroot -p dbname

# taking a snapshot of a btrfs partition
btrfs send /snapshots/$date | pv | btrfs receive /mnt/backup/root

I don't know of any commands that give one-line progress bars in the style of pv or wget, but there are plenty of simple Bash/Perl/sed scripts that will add that functionality, as others have shared here.

Solution 2:

You can use zenity to create simple GTK dialog windows. One of the available options is a progress bar dialog.

You create such a window using zenity --progress. To make it useful, you should specify more information by adding some of the options below (excerpt from man zenity):

   Progress options
   --text=STRING
          Set the dialog text
   --percentage=INT
          Set initial percentage
   --auto-close
          Close dialog when 100% has been reached
   --auto-kill
          Kill parent process if cancel button is pressed
   --pulsate
          Pulsate progress bar
   --no-cancel
          Hides the cancel button

There are two modes:

  • pulsating: The progress bar is pulsating, it just indicates that something is running, but does not tell anything about the progress. You do this by setting the --pulsating option.

  • manual: You have to pipe the current progress percentage to the zenity command's standard input to update the progress bar.
    An example for this could look like that below. Note that the previous commands are grouped to a subshell so that all the output is redirected to the zenity dialog and not just that of the last command:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress