Bash Progress Bar and Python Terminal Progress Bars

Terminal progress bar illustration with blocks filling from left to right

A terminal progress bar is useful only when your script knows how much work is complete. Use tqdm for a Python loop with a known total, or use Bash printf with a carriage return when the script owns the counter.

Use a progress bar only when you can measure work

A percentage needs a numerator and a total. File counts, byte totals, and a fixed list of jobs work well. A spinner is the honest alternative when a command may take time but cannot report completion.

Terminal output is easier to follow when you already know how Linux command-line navigation and file commands work. If the job runs from a script, shell scripting basics and cron jobs gives the surrounding execution model.

Show Python loop progress with tqdm

tqdm wraps an iterable and writes updates to the terminal while your loop advances. It can calculate a percentage, item count, rate, and estimated remaining time because range(5) has a length.

python -m pip install tqdm

Save the following file as python_progress.py. The loop sleeps only to make the changing display visible. Replace sleep with the work that processes each item.

from time import sleep
from tqdm import trange

for _ in trange(5, desc='Copying files', unit='file', ncols=56):
    sleep(0.03)

Run the script with the Python environment where you installed tqdm.

./venv/bin/python python_progress.py
“source_url”: “https://www.linuxfordevices.com/wp-content/uploads/2026/08/python-progress.png” }
Python tqdm progress meter showing Copying files complete at 5 of 5

The final 5/5 line shows that every loop iteration finished. tqdm redraws a single terminal line through carriage-return control characters, so its changing states may appear as separate lines in a captured terminal image.

Build a Bash progress bar with printf

Bash has no built-in percentage widget, but it can redraw one line. This function derives filled and empty widths from the counter, then printf returns the cursor to the start of that line before the next update.

#!/usr/bin/env bash
set -euo pipefail

for current in $(seq 0 10); do
  width=20
  filled=$((current * width / 10))
  empty=$((width - filled))
  printf -v filled_bar '%*s' "$filled" ''
  printf -v empty_bar '%*s' "$empty" ''
  filled_bar=${filled_bar// /#}
  empty_bar=${empty_bar// /-}
  printf '\r[%s%s] %3d%%' "$filled_bar" "$empty_bar" "$((current * 10))"
  sleep 0.03
done
printf '\n'

Save it as bash_progress.sh and run the exact command below.

bash bash_progress.sh
“source_url”: “https://www.linuxfordevices.com/wp-content/uploads/2026/08/bash-progress.png” }
Bash script progress bar updating from 0 percent to 100 percent

At 0%, the bar contains only dashes. At 100%, all twenty positions are filled. Keep printf rather than echo here because printf gives the script exact control over the carriage return and percentage formatting.

Choose the display that matches the task

Use a determinate bar when you know the total. Use a spinner when waiting for a service, download, or subprocess that exposes no count. A bar that guesses completion is worse than a spinner because it claims information the program does not have.

  1. Wrap a sized Python iterable with tqdm when each iteration represents one unit of work.
  2. Track current and total in Bash when your script controls the loop.
  3. Use a spinner when the program cannot measure a total.
  4. Send progress output to the terminal, not a data stream that another command must parse.

Existing Python progress displays

The retained examples below show distinct Python terminal displays. Keep the display simple when the task only needs a count and percentage.

tqdm is a library in Python which is used for creating Progress Meters or Progress Bars
tqdm library

This tqdm example shows a determinate meter. Use it when the iterable itself supplies the total.

Animated Python bars and spinners

alive-progress adds an animated meter with throughput and estimated time, which earns its place only when rate feedback changes how you monitor a long-running loop.

A new kind of Progress Bar, with real-time throughput, ETA, and very cool animations!
alive_progress library

The animation is visual feedback, not a substitute for a correct total.

This second alive-progress state shows the meter later in the same kind of workload.

A new kind of Progress Bar, with real-time throughput, ETA, and very cool animations!
alive_progress library

Keep it only when the changing rate or remaining-time display helps you monitor a long operation.

Halo shows a spinner for work without a known total.

Halo - Beautiful spinners for terminal, IPython and Jupyter
halo library

Use a spinner instead of inventing a percentage for an opaque subprocess.

Yaspin is another spinner option for a task that has started but cannot expose a total.

Yaspin provides a full-featured terminal spinner to show the progress during long-hanging operations.
yaspin library

A spinner should stop with a success or failure message so the terminal does not leave an ambiguous active state.

Existing Bash display examples

The retained Bash captures show a text bar, an animated terminal state, and gauge-style interfaces. A plain text bar remains the best fit for a portable script that only needs Bash and a terminal.

bash terminal progress bar
bash progress bar

This captured bar shows the same filled-versus-empty idea used in the current Bash example.

The next state demonstrates that a progress display can animate while work continues.

bash terminal progress  bar with animations
bash progress bar

Animation is optional. Preserve readable counts or percentages when a log will be reviewed later.

A gauge interface can help when a script is intentionally interactive.

bash gui progress bar
gui progress bar

Before choosing an interactive gauge, check which shell is running your script and whether the target system has its required utility.

The final gauge example keeps that interface distinction visible.

bash gui progress bar
gui progress bar

For an unattended job, send concise status to a log and reserve terminal redraws for an interactive session.

Avoid broken progress output

A progress bar should end with a newline. Without it, the next shell prompt lands on the same line as the completed bar. If you distribute the Bash script, use chmod and ownership guidance before making it executable.

Terminal configuration can also change colors, prompts, and startup behavior. Bash profile and bashrc settings explain where those settings belong. Keep the progress calculation in the script rather than in either startup file.

Frequently asked questions

Start with tqdm when a Python iterable already has a length. In Bash, keep the counter and total next to the work loop so the displayed percentage remains tied to work the script can measure.