Create Bash Progress Bar like a PRO: Don't be a Rookie!


Written by - Deepak Prasad

Whether you're a system administrator, developer, or a scripting enthusiast, you've probably found yourself working with Bash at some point. One common challenge faced during script execution is understanding how much of a task has been completed and how much is left to do. This is especially true for tasks that take a significant amount of time to complete. Enter the "Bash progress bar"—a simple yet effective way to visually represent the completion status of a long-running operation.

In the previous article we explored different methods to create progress par using Python programming language. In this comprehensive guide, we will explore everything you need to know about creating and customizing Bash progress bars. From the very basics to advanced techniques, this article aims to provide a one-stop resource for all skill levels. Whether you are a beginner just getting started with Bash or an experienced professional looking to enhance your scripts, there's something here for everyone.

By the end of this article, you'll be well-equipped to implement your own Bash progress bars, improving the user experience and the functionality of your Bash scripts.

 

Create a simple progress bar

Creating a Bash progress bar can be a simple yet powerful way to enhance the user experience and convey progress for long-running tasks. Below is a basic example of a Bash progress bar script that uses the echo command.

#!/bin/bash

# Total number of steps
total_steps=20

# Initial progress
progress=0

# Display initial state
echo -n "[--------------------] 0% "

# Simulation of a task
while [ $progress -le $total_steps ]; do
    # Calculate the number of '#' to display
    let filled_slots=progress*20/total_steps

    # Create the progress bar string
    bar=""
    for ((i=0; i<$filled_slots; i++)); do
        bar="${bar}#"
    done

    # Create the remaining bar string
    for ((i=filled_slots; i<20; i++)); do
        bar="${bar}-"
    done

    # Calculate percentage
    let percentage=progress*100/total_steps

    # Print the progress bar
    echo -ne "\r[${bar}] ${percentage}% "

    # Simulate a task by sleeping for 0.1 seconds
    sleep 0.1

    # Update progress
    let progress++
done

echo # Print a newline

Explanation

  • total_steps=20: The total number of steps required to complete the task.
  • progress=0: Indicates the current progress of the task.
  • The echo -n "[--------------------] 0%" line prints the initial state of the Bash progress bar without a trailing newline.
  • We use a while loop to simulate a task. Within this loop, we do the following:

Calculate Filled Slots: The number of '#' characters required is calculated based on the progress.

let filled_slots=progress*20/total_steps

Create Progress Bar String: Empty strings ("-") and filled strings ("#"), are concatenated to create the progress bar.

bar=""
for ((i=0; i<$filled_slots; i++)); do
    bar="${bar}#"
done

Print the Bash Progress Bar: We use echo -ne to print the progress bar, where:

  • -n ensures that the cursor doesn't move to the next line.
  • -e enables the interpretation of backslash escapes, like \r (Carriage Return).
echo -ne "\r[${bar}] ${percentage}% "

Sleep: sleep 0.1 is used to simulate some task running for a brief period.

 

Create Multi-step Progress Bar

Creating a multi-step Bash progress bar can add more granularity to your scripts by allowing you to track the completion of various subtasks within a larger operation. Let's consider a scenario where you have a script that performs three major tasks. Each task takes a different amount of time to complete, and you want to display a separate progress bar for each task.

#!/bin/bash

# Function to display a progress bar
display_progress_bar() {
    local total_steps=$1
    local progress=0
    local bar=""

    echo -n "[--------------------] 0% "

    while [ $progress -le $total_steps ]; do
        let filled_slots=progress*20/total_steps
        bar=""

        for ((i=0; i<$filled_slots; i++)); do
            bar="${bar}#"
        done

        for ((i=filled_slots; i<20; i++)); do
            bar="${bar}-"
        done

        let percentage=progress*100/total_steps
        echo -ne "\r[${bar}] ${percentage}% "

        sleep 0.1
        let progress++
    done

    echo
}

# Task 1
echo "Starting Task 1..."
display_progress_bar 20

# Task 2
echo "Starting Task 2..."
display_progress_bar 30

# Task 3
echo "Starting Task 3..."
display_progress_bar 25

echo "All tasks completed!"

Explanation

This function encapsulates the logic for displaying a single progress bar. It takes one argument, total_steps, which indicates the total number of steps for the particular task.

Each task is represented by a separate call to the display_progress_bar function, with a varying number of total steps.

Task 1: Takes 20 steps to complete.

echo "Starting Task 1..."
display_progress_bar 20

Task 2: Takes 30 steps to complete.

echo "Starting Task 2..."
display_progress_bar 30

Task 3: Takes 25 steps to complete.

echo "Starting Task 3..."
display_progress_bar 25

 

Create Progress Bar with Percentage Display

Displaying the percentage of completion alongside the graphical representation can make a shell script progress bar more informative and easier to interpret. Here's an example that shows how to create a progress bar in a shell script that also displays the percentage of the task completed.

#!/bin/bash

# Function to display progress bar with percentage
display_progress_bar_with_percentage() {
    local total_steps=$1
    local progress=0
    local bar=""
    local percentage=0

    echo -n "[--------------------] 0% "

    while [ $progress -le $total_steps ]; do
        let filled_slots=progress*20/total_steps
        bar=""
        
        # Generate the filled portion of the bar
        for ((i=0; i<$filled_slots; i++)); do
            bar="${bar}#"
        done

        # Generate the unfilled portion of the bar
        for ((i=filled_slots; i<20; i++)); do
            bar="${bar}-"
        done

        # Calculate the percentage of completion
        let percentage=progress*100/total_steps

        # Display the bar and percentage
        echo -ne "\r[${bar}] ${percentage}% "

        # Simulate some work
        sleep 0.1

        # Increment the progress
        let progress++
    done

    echo # Move to the next line after completion
}

# Main execution
echo "Starting the operation..."
display_progress_bar_with_percentage 100
echo "Operation completed!"

Explanation

Variables

  • total_steps: The total number of steps that the operation will take.
  • progress: Keeps track of the current progress.
  • bar: Stores the visual representation of the shell script progress bar.
  • percentage: Stores the calculated percentage of completion.

While Loop

Within the while loop, the script performs the following operations:

Calculate Filled Slots: Determines how many # characters are needed in the progress bar.

let filled_slots=progress*20/total_steps

Generate Progress Bar: Filled (#) and unfilled (-) portions of the progress bar are created.

for ((i=0; i<$filled_slots; i++)); do
    bar="${bar}#"
done

Calculate Percentage: Determines the percentage of the task that has been completed.

let percentage=progress*100/total_steps

Display Progress Bar and Percentage: Both the graphical progress bar and the percentage of completion are displayed using the echo command.

echo -ne "\r[${bar}] ${percentage}% "

Simulate Work: sleep 0.1 is used to simulate the operation we are tracking.

 

Create Bash Progress Bar with Dynamic Sizing

Dynamic sizing in a Bash progress bar allows you to adjust the length of the progress bar according to a specified parameter or even the terminal window size. This enhances the user experience by providing a more flexible and visually pleasing display.

#!/bin/bash

# Function to display a dynamically sized progress bar
display_dynamic_progress_bar() {
    local total_steps=$1
    local progress=0
    local terminal_width=$(tput cols)

    # Deduct 10 to leave space for percentage display and brackets
    let bar_width=terminal_width-10

    while [ $progress -le $total_steps ]; do
        let filled_slots=progress*bar_width/total_steps
        bar=""

        # Generate the filled portion of the bar
        for ((i=0; i<$filled_slots; i++)); do
            bar="${bar}#"
        done

        # Generate the unfilled portion of the bar
        for ((i=filled_slots; i<bar_width; i++)); do
            bar="${bar}-"
        done

        # Calculate the percentage of completion
        let percentage=progress*100/total_steps

        # Display the bar and percentage
        echo -ne "\r[${bar}] ${percentage}% "

        # Simulate some work
        sleep 0.1

        # Increment the progress
        let progress++
    done

    echo # Move to the next line after completion
}

# Main execution
echo "Starting the operation..."
display_dynamic_progress_bar 100
echo "Operation completed!"

Explanation

Fetching Terminal Width

The script first fetches the terminal's width using the command tput cols, and stores it in the variable terminal_width.

local terminal_width=$(tput cols)

Calculating Dynamic Bar Width

We then subtract 10 from terminal_width to accommodate the brackets [ ] and percentage display.

let bar_width=terminal_width-10

Dynamic Bar Sizing in While Loop

Within the loop, the script dynamically adjusts the number of filled (#) and unfilled (-) slots based on the calculated bar_width.

let filled_slots=progress*bar_width/total_steps

The rest of the script is similar to the previous examples, but now it utilizes this dynamically calculated bar_width.

 

Customizing Progress Bar Styles

Creating visually appealing and informative progress indicators is crucial for enhancing user experience. Various styles of progress bars can be used, each serving a different purpose and aesthetic. In this section, we'll look at different types of Bash progress bars and shell script progress bars, including horizontal and vertical progress bars, colored progress bars, and text-based indicators like spinners.

 

1. Horizontal Bash Progress Bar

The horizontal progress bar is the most traditional and commonly used style.

#!/bin/bash
total_steps=20
for ((progress=0; progress<=total_steps; progress++)); do
    let filled_slots=progress*20/total_steps
    bar=""
    for ((i=0; i<$filled_slots; i++)); do
        bar="${bar}#"
    done
    echo -ne "\r[${bar}]"
    sleep 0.1
done

 

2. Vertical Shell Script Progress Bar

Vertical progress bars occupy less horizontal space and can be useful in specific scenarios.

#!/bin/bash
total_steps=20
for ((progress=0; progress<=total_steps; progress++)); do
    echo -ne "\e[20A" # Move 20 lines up
    for ((i=0; i<progress; i++)); do
        echo "#"
    done
    for ((i=progress; i<total_steps; i++)); do
        echo "-"
    done
    sleep 0.1
    echo -e "\e[20B" # Move 20 lines down
done

 

3. Colored Bash Progress Bar

Adding color can make your bash progress bar more visually appealing. You can use ANSI escape codes for coloring.

#!/bin/bash
echo -ne "\033[31m" # Set color to red
total_steps=20
for ((progress=0; progress<=total_steps; progress++)); do
    let filled_slots=progress*20/total_steps
    bar=""
    for ((i=0; i<$filled_slots; i++)); do
        bar="${bar}#"
    done
    echo -ne "\r[${bar}]"
    sleep 0.1
done
echo -ne "\033[0m" # Reset color

 

4. Text-Based Progress Indicators (Spinner)

Spinners are another form of shell script progress bar that are useful when the total steps are unknown.

#!/bin/bash
spinner="/|\\-/"

echo -n "Processing "
while :; do
    for i in {0..3}; do
        echo -ne "\b${spinner:i:1}"
        sleep 0.1
    done
done

 

5. Adding Additional Information (e.g., Time Remaining)

Adding time estimates to your progress bar can make it more informative. Here's a Bash progress bar that also estimates the time remaining.

#!/bin/bash
start_time=$(date +%s)
total_steps=100
for ((i=1; i<=total_steps; i++)); do
  current_time=$(date +%s)
  elapsed_time=$((current_time - start_time))
  estimated_time=$((elapsed_time * total_steps / i - elapsed_time))
  echo -ne "\rProgress: [$i/$total_steps] - Estimated Time Remaining: ${estimated_time}s"
  sleep 0.1
done
echo # Newline

 

6. Customizing Appearance

You can customize the appearance of the shell script progress bar by using different characters or adding colors.

#!/bin/bash
total_steps=20
echo -ne "\033[34m" # Set color to blue
for ((progress=0; progress<=total_steps; progress++)); do
  let filled_slots=progress*40/total_steps
  bar=""
  for ((i=0; i<$filled_slots; i++)); do
    bar="${bar}="
  done
  echo -ne "\r[${bar}]"
  sleep 0.1
done
echo -ne "\033[0m" # Reset color

 

7. Keyboard Interruptions

It's useful to allow the user to interrupt the bash progress bar cleanly. Here's how you can capture keyboard interruptions like Ctrl+C in your script.

#!/bin/bash
trap "echo; echo 'Operation aborted.'; exit 1" SIGINT SIGTERM

total_steps=100
for ((i=1; i<=total_steps; i++)); do
  sleep 0.1
  echo -ne "\rProgress: [$i/$total_steps]"
done

echo # Newline

In this script, pressing Ctrl+C will trigger the message "Operation aborted" and the script will exit.

 

Using External Libraries to create Progress Bar

Using external libraries or commands can provide a quick and feature-rich way to implement progress bars in your Bash scripts. Here, we'll look at some popular options like pv, dialog, and third-party Bash libraries to add bash progress bars or indicators.

 

1. Using pv command

The pv (Pipe Viewer) command allows you to view the progress of data through a pipeline. It's extremely handy for tracking the status of commands that process data.

First you will need to install pv as it is not installed by default in most distributions:

# Install pv on Debian/Ubuntu
sudo apt update
sudo apt install pv

# Install pv on CentOS/RHEL/Fedora
sudo yum install pv
# Or for newer Fedora versions
# sudo dnf install pv

# Install pv on macOS
brew install pv

Here is a simple example to use pv while performing a copy operation to display bash progress bar.

# Copying a file with progress
cat large_file.txt | pv -s $(stat -c %s large_file.txt) > output.txt

In this example, pv shows a text-based bash progress bar indicating how much data has been processed.

You can use pv to monitor the transfer rate and progress when compressing a file with gzip.

pv large_file.txt | gzip > large_file.txt.gz

Here's how you can see a progress bar when searching for a particular string in a large text file.

pv large_file.txt | grep "search_string"

When exporting a large MySQL database, you can track the progress as follows:

mysqldump -u username -p database_name | pv -i 0.5 > database_dump.sql

 

2. Using dialog command

To install diag utility, you can use the different package managers such as yum, apt or brew based on your distribution:

# Install dialog on Debian/Ubuntu
sudo apt update
sudo apt install dialog

# Install dialog on CentOS/RHEL/Fedora
sudo yum install dialog
# Or for newer Fedora versions
# sudo dnf install dialog

# Install dialog on macOS
brew install dialog

The dialog command allows you to create a variety of user-interface widgets in a shell script, including a GUI-like progress box.

#!/bin/bash
(
for i in {0..100}; do
    echo $i
    sleep 0.1
done
) | dialog --title "File Progress" --gauge "Please wait" 10 70 0

Here, the dialog command displays a graphical progress box that updates as the loop iterates through numbers from 0 to 100.

You can chain multiple progress bars together for multi-step operations.

#!/bin/bash
{
    for i in {0..25}; do
        echo $i
        sleep 0.1
    done
    echo "XXX"
    echo "Performing Step 1..."
    echo "XXX"
    
    for i in {26..50}; do
        echo $i
        sleep 0.1
    done
    echo "XXX"
    echo "Performing Step 2..."
    echo "XXX"

    for i in {51..100}; do
        echo $i
        sleep 0.1
    done
} | dialog --title "Multi-Step Operation" --gauge "Initializing..." 10 70 0

 

Conclusion

Progress bars are powerful tools for enhancing the user experience in shell scripting. They offer a visual indicator of an ongoing operation, making it easier for users to understand the status and estimated completion time. Throughout this article, we have explored different ways to implement a Bash progress bar, covering use cases from file transfer and script execution to data processing and web scraping. We've also dived into some tips and tricks to elevate the functionality of these progress indicators.

 

Additional Resources

 

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can reach out to him on his LinkedIn profile or join on Facebook page.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment