Aller au contenu principal

Les tableaux indexés

Notions théoriques

Pourquoi un tableau ?

Imaginez un script qui doit traiter plusieurs dossiers : /etc, /var/www, /home. Sans tableau, il faudrait soit créer une variable par dossier (dossier1, dossier2, dossier3...), soit stocker une chaîne à découper vous-même. Bash propose une structure dédiée : le tableau indexé.

Déclarer et lire un tableau

cibles=("/etc" "/var/www" "/home/user")
  • Les indices commencent à 0 : cibles[0] vaut /etc.
  • Lire un élément nécessite les accolades : ${cibles[0]}. Écrire $cibles[0] sans accolades ne fonctionne pas — Bash comprend $cibles (qui ne vaut que le premier élément) suivi du texte littéral [0].
echo "${cibles[0]}" # /etc
echo "${cibles[1]}" # /var/www
info

declare -a cibles déclare explicitement un tableau vide, mais l'affectation directe cibles=(...) suffit dans la grande majorité des cas.

Les propriétés utiles d'un tableau

ExpressionRésultat
${cibles[@]}tous les éléments du tableau
${#cibles[@]}le nombre d'éléments
${!cibles[@]}la liste des indices utilisés
${#cibles[1]}la longueur de l'élément à l'indice 1 (pas le nombre d'éléments !)
attention

${#cibles[@]} (nombre d'éléments) et ${#cibles[1]} (longueur d'une chaîne) se ressemblent beaucoup mais n'ont rien à voir. Une confusion fréquente chez les débutants.

Modifier un tableau

cibles+=("/opt") # ajoute un élément à la fin
cibles[1]="/var/log" # remplace l'élément d'indice 1
unset 'cibles[1]' # supprime l'élément d'indice 1
attention

Après un unset 'cibles[1]', l'indice 1 disparaît mais les autres indices ne sont pas renumérotés : le tableau garde un « trou ». ${!cibles[@]} révèle alors des indices non consécutifs (0 2 par exemple).

Parcourir un tableau

for cible in "${cibles[@]}"; do
echo "Traitement de : $cible"
done
danger

Le quoting change tout ici. "${cibles[@]}" donne un élément par itération, même si un élément contient un espace. Sans les guillemets, ${cibles[@]} casse chaque élément sur les espaces, comme n'importe quelle variable non quotée. Prenez l'habitude de toujours écrire "${cibles[@]}".

"${cibles[*]}" (avec une étoile) produit au contraire une seule chaîne, tous les éléments joints par le premier caractère de IFS (un espace par défaut) — rarement ce que vous voulez dans une boucle for.

Vous pouvez aussi parcourir les indices directement, utile si vous avez besoin du numéro de position :

for i in "${!cibles[@]}"; do
echo "$i : ${cibles[$i]}"
done

Remplir un tableau

Un tableau peut être rempli depuis les arguments du script :

cibles=("$@")

ou depuis un fichier, une ligne par élément :

mapfile -t lignes < liste.txt
astuce

Préférez mapfile -t à l'ancienne astuce arr=( $(cat fichier) ) : cette dernière découpe sur les espaces en plus des retours à la ligne, et casse dès qu'une ligne contient un espace. mapfile -t lit une ligne = un élément, sans surprise. L'option -t retire le retour à la ligne final de chaque élément.

info

Un sous-ensemble de tableau est possible avec ${cibles[@]:1:2} (à partir de l'indice 1, sur 2 éléments) — une syntaxe rarement indispensable, à connaître pour la reconnaître dans du code existant.

Bash propose aussi les tableaux associatifs (declare -A stats), où l'indice est une chaîne au lieu d'un nombre (stats[erreurs]=3). Nous n'irons pas plus loin ici, mais vous les recroiserez peut-être dans des scripts plus avancés.

Exemple pratique

#!/bin/bash
# Script : surveiller.sh
# Rôle : vérifier l'état de plusieurs services

services=("ssh" "cron" "nginx")
echecs=()

for service in "${services[@]}"; do
if systemctl is-active --quiet "$service"; then
echo "OK : $service"
else
echo "KO : $service"
echecs+=("$service")
fi
done

echo "---"
echo "${#echecs[@]} service(s) en échec sur ${#services[@]}."

Test de mémorisation/compréhension


Que renvoie ${#tab[@]} ?


Quel est le premier indice d'un tableau Bash ?


Dans un for, quelle est la bonne façon de parcourir un tableau sans risquer de casser les éléments contenant un espace ?


Comment ajouter un élément à la fin d'un tableau existant ?


TP pour réfléchir et résoudre des problèmes

Nous poursuivons sauvegarde.sh : il doit maintenant accepter plusieurs dossiers en une seule exécution.

Étape 1 — Stocker les arguments dans un tableau


Bonne pratique - Un tableau plutôt que des $1, $2, $3...

Dès qu'un script doit traiter un nombre variable d'éléments similaires, un tableau rend le code plus court et plus robuste qu'une suite de $1, $2, $3.

Étape 2 — Boucler sur le tableau


Bonne pratique - Toujours quoter le tableau dans un for

« Quoter le tableau », c'est écrire "${tab[@]}" entre guillemets doubles plutôt que ${tab[@]} sans guillemets. C'est la seule forme qui garantit qu'un dossier contenant un espace dans son nom reste traité comme un seul élément, pas comme plusieurs.

Étape 3 — Suivre les échecs dans un second tableau


Bonne pratique - Accumuler plutôt qu'afficher immédiatement

Collecter les échecs dans un tableau permet d'afficher un bilan clair à la fin du script, plutôt que de noyer l'utilisateur sous des messages d'erreur dispersés tout au long de l'exécution.

Étape 4 — Afficher le bilan final


Bonne pratique - Une étoile pour un affichage groupé

Pour un simple message récapitulatif, "${ECHECS[*]}" (avec une étoile) est adapté : vous voulez ici une seule chaîne lisible, pas un traitement élément par élément.

📌 Une solution