Aller au contenu principal

Linux - Utiliser une barre de progression dans vos scripts

Ajoutez une barre de progression visuelle à vos scripts Bash sous Linux. Ce guide vous montre comment implémenter facilement une barre de progression pour suivre des jobs concurrents, visualiser l'avancement et améliorer votre interface dans le terminal.

· 4 minutes de lecture
Voir la source
Christophe
Amoureux de Markdown, WSL et Docker ~ Curieux insatiable.
Cet article existe aussi en anglais — lire la version originale.

Traduction automatique

Cette traduction a été produite par une IA. Elle peut contenir des contresens ou des maladresses, en particulier sur les termes techniques. En cas de doute, consultez l'article de référence en anglais — c'est lui qui fait foi.

Cet article a plus d'un an, mais il a été relu le 30 juillet 2026 — son contenu est toujours exact.

Linux - Utiliser une barre de progression dans vos scripts

⚡
TL;DR

Cet article de suivi ajoute une barre de progression visuelle aux scripts Bash (dans la continuité de l'article précédent sur les jobs parallèles) à l'aide d'un helper réutilisable progress_bar.sh : sourcez-le, faites passer la sortie de votre boucle dans progress_bar::process "Doing some stuff" 50, et affichez Progress=N depuis l'intérieur de la boucle pour piloter la barre — pratique pour les traitements par lots longs comme des uploads vers une API pilotés par un CSV.

Dans mon article précédent, Linux - Tirez parti du nombre de CPU dont vous disposez ; lancez des jobs concurrents, nous avons vu comment lancer des jobs en parallèle.

La prochaine chose sympa, c'est d'afficher une barre de progression dans votre console. Ça présente plusieurs avantages : une vue claire de ce qui est fait et de ce qui reste à faire, et une interface agréable.

Quand le nombre d'éléments n'est pas connu à l'avance, un compteur en direct est plus adapté ; voyez Compter en continu le nombre de fichiers d'un dossier avec inotifywait. Et pour garder une trace de ce qui s'est passé une fois la barre disparue, Bash - Script pour ajouter des fonctionnalités de log à votre script.

Il y a quelques mois, j'ai trouvé cet article de blog français dans mes flux RSS : https://xieme-art.org/post/bash-avance-barre-de-progression/ et, juste, wow !!!

Amusons-nous avec ça.

Résultat​

Barre de progression

C'est une simple boucle Bash, sans aucun outil externe, qui pilote une barre de progression en direct dans la console.

Pourquoi ça fonctionne​

Un script doit faire trois choses pour obtenir cette barre :

  1. Sourcer le script progress_bar.sh (merci à ephase) ;
  2. Lancer la fonction qui fait le vrai travail d'une manière particulière : pas juste main mais main > >(progress_bar::process "Doing some stuff" 50). Le chiffre 50 doit correspondre au nombre d'itérations de la boucle ;
  3. Depuis l'intérieur de cette fonction, afficher une seule chose dans la console avec echo : Progress= suivi d'un nombre (de 1 à 50) — c'est le signal que la barre lit pour avancer.

Pas si compliqué, non ?

Créer demo.sh​

D'abord, créez un nouveau dossier sur votre disque et déplacez-vous dedans : mkdir /tmp/progress && cd $_.

Ensuite, créez un fichier demo.sh dans ce dossier et copiez/collez le script bash ci-dessous :

#!/bin/bash
set -euo pipefail
function demo {
echo "Progress=$1"
sleep 0.1
return 0
}
function main {
for i in {1..50}; do
demo "$i"
done
}
source "progress_bar.sh"
main > >(progress_bar::process "Doing some stuff" 50)

Ce script bash exécute une boucle qui appelle 50 fois une fonction demo, puis redirige la sortie vers un processus de barre de progression. Le script charge d'abord un fichier externe contenant la logique de la barre de progression, puis lance la fonction main avec la sortie canalisée vers progress_bar::process pour afficher la progression de façon visuelle.

Rendez le script exécutable en lançant chmod +x ./demo.sh.

Créer progress_bar.sh​

Voici le contenu à copier/coller dans un fichier appelé progress_bar.sh, créé dans le même dossier que demo.sh.

Créez donc un nouveau fichier sur votre disque dur ; nommez-le progress_bar.sh et copiez/collez le contenu ci-dessous dedans.

#!/usr/bin/env bash
# region - Intro block -----------------------------------------------
#
# Progress bar
#
# ## How to use this script?
#
# Just include this script in your own Bash like this `source progress_bar.sh`
#
# Now, you can use any public functions defined here like `progress_bar::draw``.
#
# ## Example
#
# The example below will just loop for 1 till 50 and the most important part is the "Progress=${i}"
# echo statement. The progression of the bar depends on a regex defined in the progress_bar::process() function.
#
# ```bash
# function main() {
# for i in {1..50}
# do
# echo "Progress=${i}"
# sleep 0.1
# done
# }
#
# main > >(progress_bar::process "Doing some stuff" 50)
# ```
#
# ## Namespace
#
# `progress_bar::`
#
# cspell:ignore endregion
#
# shellcheck disable=SC1090,SC1091
#
# ## Source
#
# The source comes from a French blog post:
# https://xieme-art.org/post/bash-avance-barre-de-progression/
#
# shellcheck disable=SC2059
#
# endregion - Intro block --------------------------------------------
# let script exit if an unset variable is used or if a command fails
set -o nounset
set -o errexit
# The different bar to display (done)
PROGRESS_BAR_CHAR=(█ ▒)
# Show or not the introduction text (f.i. "Doing some stuff")
PROGRESS_BAR_DISPLAY_INFO=1
PROGRESS_BAR_DISPLAY_COMP=1
# Display template
PROGRESS_BAR_INFO_TEMPLATE=' %s [ %3d/%3d ] '
PROGRESS_BAR_COMP_TEMPLATE=' %3d%% '
PROGRESS_BAR_TEMPLATE='\033[1m%s%s\033[0m%s%s\r'
# region - private function progress_bar::__change_column_size
#
# ## Description
#
# This function will capture de WINCH signal. That one is fired by Linux when
# the size of the window (i.e. the console) is updated so allow us to retrieve the
# max. number of columns that can fit in the window.
#
# endregion
function progress_bar::__change_column_size() {
printf >&2 "%${COLUMNS}s" ""
printf >&2 "\033[0K\r"
COLUMNS=$(tput cols)
}
# region - private function progress_bar::__draw
#
# ## Description
#
# Draw the progress bar / progression
#
# endregion
function progress_bar::__draw() {
# function parameters
local -r progress=${1?"progress is mandatory"}
local -r total=${2?"total elements is mandatory"}
local -r info=${3:-"In progress"}
# function local variables
local progress_segment
local todo_segment
local info_segment=""
local comp_segment=""
if [[ ${PROGRESS_BAR_DISPLAY_INFO:-1} -eq 1 ]]; then
printf -v info_segment "${PROGRESS_BAR_INFO_TEMPLATE}" \
"$info" "$progress" "$total"
fi
local -r progress_ratio=$((progress * 100 / total))
if [[ ${PROGRESS_BAR_DISPLAY_COMP:-0} -eq 1 ]]; then
printf -v comp_segment "${PROGRESS_BAR_COMP_TEMPLATE}" \
"$progress_ratio"
fi
# progress bar construction
# calculate each element sizes, bar must fit in ou screen
local -r bar_size=$((COLUMNS - ${#info_segment} - ${#comp_segment}))
local -r progress_segment_size=$((bar_size * progress_ratio / 100))
local -r todo_segment_size=$((bar_size - progress_segment_size))
printf -v progress_segment "%${progress_segment_size}s" ""
printf -v todo_segment "%${todo_segment_size}s" ""
printf >&2 "$PROGRESS_BAR_TEMPLATE" \
"$info_segment" \
"${progress_segment// /${PROGRESS_BAR_CHAR[0]}}" \
"${todo_segment// /${PROGRESS_BAR_CHAR[1]}}" \
"$comp_segment"
}
# region - public function progress_bar::process
#
# ## Description
#
# Display a progress bar
#
# ## Example
#
# ```bash
# function main() {
# for i in {1..50}
# do
# echo "Progress=${i}"
# sleep 0.1
# done
# }
#
# main > >(progress_bar::process "Doing some stuff" 50)
# ```
#
# ## Parameters
#
# * @arg $1 The text to display like "Upload in progress"
# * @arg $2 The number of positions in the bar (f.i. if there are 4 rows to proceed, it has to be initialize to 4)
#
# endregion
function progress_bar::process() {
local -r action="${1:-Upload in progress}"
local -r max=${2:-100}
# Capture the resize of the window so the progress bar becomes responsive
trap progress_bar::__change_column_size WINCH
while read -r line; do
# Each line with "Progress=(digit)" will increase the progress bar
if [[ $line =~ Progress=([[:digit:]]{1,}) ]]; then
progress_bar::__draw "${BASH_REMATCH[1]}" "${max}" "${action}"
fi
done
}
# This script didn't contains executable code; only helpers.
sourced=0
(return 0 2> /dev/null) && sourced=1 || sourced=0
if [ "${sourced}" -eq "0" ]; then
printf "\033[1;31m%s\033[0m\n" "ERROR, the $0 script is meant to be sourced. Try 'source $0' and use public functions." >&2 # Write on stderr
exit 1
fi
return 0

Ce script fournit une barre de progression réutilisable pour Bash. Il s'utilise en le chargeant avec source, puis en canalisant la sortie d'une boucle vers la fonction progress_bar::process, qui capte les lignes contenant « Progress=nombre » et affiche une barre mise à jour en temps réel. Le script gère aussi le redimensionnement de la fenêtre de terminal pour adapter la barre de progression.

Place à l'exécution​

Retournez simplement dans la console, lancez ./demo.sh et... wow, c'est vraiment chouette — vous obtenez la barre montrée plus haut.

Dans un cas réel, j'ai implémenté cette fonctionnalité dans un script Bash où je dois lire un fichier CSV et, pour chaque enregistrement récupéré dans le fichier, lancer une commande curl pour appeler une API RESTful en POST et uploader un PDF.

Et, quand le script est lancé de manière interactive, la sortie à l'écran est vraiment pratique et terriblement efficace.

Bien sûr, j'utilise aussi un fichier de log où je redirige un maximum d'informations.


🦋 Rejoignez la conversation sur BlueskyUn compte Bluesky gratuit est nécessaire pour aimer, repartager ou commenter. Ce bloc interroge l'API publique de Bluesky directement depuis votre navigateur (sans cookie, sans connexion) — votre adresse IP parvient donc aux serveurs de Bluesky dès que cette section se charge.

Chargement des commentaires…

Cet article vous a-t-il été utile ?
Avez-vous suivi les étapes de cet article ?