Aller au contenu
Administration Linux medium

Variables et paramètres Bash

9 min de lecture

Les variables Bash ne sont pas des types. Une variable est une chaîne de caractères — et l’interprétation comme nombre, tableau ou chemin dépend du contexte dans lequel vous l’utilisez. Comprendre ce modèle simple mais puissant vous permet d’exploiter l’expansion de paramètre, l’arithmétique entière et les tableaux pour écrire des scripts concis et robustes.

  • Déclarer des variables et interpréter les variables spéciales $?, $#, $@, $0, $$
  • Calculer avec $(( )) sans appeler bc ou expr
  • Appliquer des valeurs par défaut avec ${var:-valeur} pour les scripts configurables
  • Extraire et transformer des chaînes sans awk ni sed
  • Créer des tableaux indexés et associatifs pour grouper des données
  • Contrôler la portée d’une variable avec export et local

Les variables et leurs expansions interviennent dans presque tous les scripts de niveau intermédiaire :

  • lire la configuration depuis des variables d’environnement avec une valeur par défaut si elles ne sont pas définies (${TIMEOUT:-30})
  • extraire le nom de fichier ou l’extension d’un chemin sans appeler basename
  • compter les arguments passés à un script et afficher un usage si $# -lt 2
  • stocker la liste des serveurs à traiter dans un tableau et itérer dessus
  • vérifier le code de retour de la dernière commande avec $?

En préparation RHCSA, les variables spéciales ($1, $#, $@, $?) et l’arithmétique entière sont testées explicitement dans les exercices de scripting.

Une variable se déclare sans espaces autour du = :

Fenêtre de terminal
nom="Alice"
age=30
chemin="/var/log/nginx"
Fenêtre de terminal
echo "Nom : $nom, Age : $age"
# Nom : Alice, Age : 30

Les guillemets doubles permettent l’expansion des variables. Les guillemets simples les désactivent :

Fenêtre de terminal
echo "$nom" # Alice
echo '$nom' # $nom (littéral)

$() exécute une commande et capture sa sortie :

Fenêtre de terminal
date_iso=$(date '+%Y-%m-%d')
user_actuel=$(whoami)
nb_fichiers=$(ls /etc | wc -l)
echo "Date : $date_iso, Utilisateur : $user_actuel, Fichiers dans /etc : $nb_fichiers"
# Date : 2026-04-10, Utilisateur : bob, Fichiers dans /etc : 222

Ces variables sont définies automatiquement par Bash — vous ne pouvez pas les affecter directement (sauf $0 qui est en lecture seule).

VariableSignificationExemple
$0Nom du scriptdemo-variables.sh
$1$9Arguments positionnels$1 = premier argument
$#Nombre d’arguments2 si deux args passés
$@Tous les arguments (liste)"un" "deux"
$*Tous les arguments (chaîne)"un deux"
$?Code de retour du dernier programme0 = succès
$$PID du processus courant12345
$!PID du dernier processus en arrière-plan12346
Fenêtre de terminal
# Appelé : ./script.sh un deux
echo "Script : $0" # Script : ./script.sh
echo "Premier : $1" # Premier : un
echo "Nb args : $#" # Nb args : 2
echo "Tous : $@" # Tous : un deux
ls /inexistant 2>/dev/null
echo "Code retour : $?" # Code retour : 2

La différence est visible entre guillemets doubles :

Fenêtre de terminal
args=("avec espace" "arg2")
for a in "$@"; do echo "$a"; done
# → avec espace
# → arg2
for a in "$*"; do echo "$a"; done
# → avec espace arg2 (fusionné en un seul argument)

Utilisez toujours "$@" pour passer ou parcourir les arguments — "$*" écrase les espaces dans les valeurs.

$(( expression )) évalue une expression arithmétique entière :

Fenêtre de terminal
a=10; b=3
echo "$((a + b))" # 13
echo "$((a - b))" # 7
echo "$((a * b))" # 30
echo "$((a / b))" # 3 (division entière)
echo "$((a % b))" # 1 (modulo)
echo "$((a ** b))" # 1000 (puissance)

Pour incrémenter une variable, préférez l’affectation explicite (compatible set -e) :

Fenêtre de terminal
compteur=0
compteur=$((compteur + 1))
compteur=$((compteur + 5))
echo "$compteur" # 6

Bash ne gère que les entiers. Pour les calculs décimaux :

Fenêtre de terminal
echo "scale=2; 10 / 3" | bc # 3.33

L’expansion de paramètre ${ } offre bien plus que la simple substitution.

Fenêtre de terminal
# Utiliser la valeur si définie, sinon la valeur par défaut
TIMEOUT=${TIMEOUT:-30}
PREFIX=${PREFIX:-"/usr/local"}
echo "Timeout : $TIMEOUT" # Timeout : 30 (si TIMEOUT non défini)
echo "Prefix : $PREFIX" # Prefix : /usr/local
SyntaxeComportement
${var:-défaut}Retourne défaut si var est vide ou non définie
${var:=défaut}Affecte et retourne défaut si var est vide ou non définie
${var:+valeur}Retourne valeur si var est définie et non vide
${var:?message}Erreur avec message si var est vide ou non définie
# Exemple pratique : rendre un script configurable par l'environnement
#!/bin/bash
set -euo pipefail
DEST=${DEST:-"/tmp/backup"}
KEEP=${KEEP:-7}
LOG=${LOG:-"/var/log/backup.log"}
echo "Sauvegarde vers $DEST, conservation $KEEP jours, log $LOG"

Appelé sans variables : utilise les défauts. Appelé avec DEST=/mnt/nas ./script.sh : utilise /mnt/nas.

Sans appeler sed ou awk, Bash peut transformer des chaînes directement :

Fenêtre de terminal
chemin="/var/log/nginx/access.log"
echo "${#chemin}" # 25 (longueur)
echo "${chemin^^}" # /VAR/LOG/NGINX/ACCESS.LOG (majuscules)
echo "${chemin,,}" # /var/log/nginx/access.log (minuscules)
echo "${chemin##*/}" # access.log (tout ce qui est après le dernier /)
echo "${chemin%/*}" # /var/log/nginx (tout ce qui est avant le dernier /)
echo "${chemin##*.}" # log (extension)
echo "${chemin%.log}.bak" # /var/log/nginx/access.bak (remplace l'extension)
echo "${chemin/nginx/apache}" # /var/log/apache/access.log (première occurrence)

Tableau récapitulatif :

SyntaxeRésultat
${#var}Longueur de la chaîne
${var^^}Tout en majuscules
${var,,}Tout en minuscules
${var##motif}Supprime le plus long préfixe correspondant au motif
${var%%motif}Supprime le plus long suffixe correspondant au motif
${var#motif}Supprime le plus court préfixe
${var%motif}Supprime le plus court suffixe
${var/motif/remp}Remplace la première occurrence
${var//motif/remp}Remplace toutes les occurrences

Un tableau stocke plusieurs valeurs accessibles par index entier (commence à 0) :

Fenêtre de terminal
serveurs=("web01" "web02" "db01" "cache01")
echo "${serveurs[0]}" # web01
echo "${serveurs[-1]}" # cache01 (dernier élément)
echo "${#serveurs[@]}" # 4 (nombre d'éléments)
echo "${serveurs[@]}" # web01 web02 db01 cache01
echo "${serveurs[@]:1:2}" # web02 db01 (slice : 2 éléments à partir de l'index 1)

Parcourir tous les éléments :

Fenêtre de terminal
for s in "${serveurs[@]}"; do
echo "$s"
done
# → web01
# → web02
# → db01
# → cache01

Ajouter un élément :

Fenêtre de terminal
serveurs+=("monitor01")
echo "${serveurs[@]}" # web01 web02 db01 cache01 monitor01

Les tableaux associatifs (declare -A) utilisent des clés textuelles — l’équivalent d’un dictionnaire :

Fenêtre de terminal
declare -A ports
ports["ssh"]=22
ports["http"]=80
ports["https"]=443
ports["mysql"]=3306
echo "${ports[ssh]}" # 22
echo "${!ports[@]}" # Toutes les clés : ssh https mysql http
echo "${ports[@]}" # Toutes les valeurs : 22 443 3306 80

Parcourir clés et valeurs :

Fenêtre de terminal
for service in "${!ports[@]}"; do
echo " $service → ${ports[$service]}"
done
# ssh → 22
# https → 443
# mysql → 3306
# http → 80

export — rendre une variable visible aux processus enfants

Section intitulée « export — rendre une variable visible aux processus enfants »
Fenêtre de terminal
LANG=fr_FR.UTF-8
export LANG
# Équivalent en une ligne :
export LANG=fr_FR.UTF-8

Une variable non exportée n’est pas transmise aux sous-processus :

Fenêtre de terminal
MA_VAR="bonjour"
bash -c 'echo $MA_VAR' # (vide — non transmis)
export MA_VAR
bash -c 'echo $MA_VAR' # bonjour

Sans local, toute affectation dans une fonction modifie la variable globale :

Fenêtre de terminal
GLOBAL="initial"
ma_fonction() {
local LOCAL="je suis local"
GLOBAL="modifié dans la fonction"
echo "Dans la fonction : $LOCAL / $GLOBAL"
}
ma_fonction
echo "Après : $GLOBAL" # modifié dans la fonction
# echo $LOCAL # bash: LOCAL: unbound variable (avec set -u)

Règle : dans toute fonction, déclarez les variables internes avec local pour éviter les effets de bord.

SymptômeCause probableSolution
Variable toujours videEspace autour du =var=valeur sans espaces
: unbound variable avec set -uVariable non initialiséeInitialiser ou utiliser ${var:-} comme défaut vide
$@ fusionne des valeurs avec espacesUtilisé sans guillemetsToujours écrire "$@"
(( expr )) stoppe le script avec set -eRésultat arithmétique = 0Utiliser var=$((var + 1))
Tableau associatif non reconnuBash < 4.0 ou sh au lieu de bashVérifier bash --version et le shebang #!/bin/bash
  • $? est le code de retour du dernier programme — à lire immédiatement, une commande suivante l’écrase.
  • "$@" passe les arguments correctement en préservant les espaces ; "$*" les fusionne.
  • ${var:-défaut} rend les scripts configurables sans condition if.
  • ${chemin##*/} extrait le nom de fichier ; ${chemin%/*} extrait le répertoire — sans appeler basename/dirname.
  • declare -A crée un tableau associatif — disponible uniquement avec Bash 4+.
  • Déclarez toujours les variables internes à une fonction avec local.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn