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
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
| Expression | Ré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 !) |
${#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
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
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
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.
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
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
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
« 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
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
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.