Scripting Bash Avancé : Maîtrise des Fonctionnalités du Shell pour l'Automatisation
Apprenez les scripts Bash avancés avec les tableaux, la substitution de processus, le mode strict, ShellCheck et l'expansion de paramètres pour une automatisation plus sûre.
Scripts Bash Avancés : Maîtrise des Fonctionnalités du Shell pour l'Automatisation
Les scripts Bash deviennent plus complexes lorsque votre script passe de quelques commandes à une véritable automatisation. Vous avez besoin d'une gestion plus sûre des variables, d'une entrée et sortie plus propres, et de moins de fichiers temporaires.
Ce guide couvre les fonctionnalités avancées des scripts Bash que vous pouvez utiliser dans les scripts de déploiement, les vérifications de logs et les tâches de maintenance. L'objectif n'est pas d'écrire du code shell astucieux. Il s'agit d'un code que vous pouvez réexécuter, déboguer et confier à un autre ingénieur.
1. Utilisez les Tableaux Bash pour de Vraies Listes
Les tableaux vous permettent de stocker plusieurs valeurs sans diviser les chaînes par des espaces. Cela compte lorsque les noms de fichiers, les noms de services ou les entrées utilisateur contiennent des espaces.
Tableaux Indexés
Les tableaux indexés sont le type le plus courant, où les éléments sont accessibles à l'aide d'un index numérique commençant à 0.
Exemple :
# Initialiser un tableau indexé
COULEURS=("rouge" "vert" "bleu" "jaune")
# Accéder aux éléments
echo "La deuxième couleur est : ${COULEURS[1]}"
# Ajouter un élément
COULEURS+=( "violet" )
# Afficher tous les éléments
echo "Toutes les couleurs : ${COULEURS[@]}"
Opérations courantes sur les tableaux :
| Opération | Syntaxe | Description |
|---|---|---|
| Obtenir le nombre d'éléments | ${#TABLEAU[@]} |
Retourne le nombre total d'éléments. |
| Obtenir la longueur d'un élément spécifique | ${#TABLEAU[index]} |
Retourne la longueur de la chaîne à un index spécifique. |
| Itération | for item in "${TABLEAU[@]}" |
Structure de boucle standard pour traiter tous les éléments. |
Mettez toujours entre guillemets les expansions de tableaux avec "${TABLEAU[@]}". Cela conserve "/var/log/mon app.log" comme un seul argument au lieu de deux.
Tableaux Associatifs
Les tableaux associatifs fonctionnent comme de petites cartes clé-valeur. Ils nécessitent Bash 4 ou version ultérieure, alors vérifiez vos systèmes cibles si vous prenez en charge des hôtes macOS plus anciens.
Vous devez déclarer un tableau associatif avec -A :
# Déclarer comme tableau associatif
declare -A MAP_CONFIG
# Assigner des paires clé-valeur
MAP_CONFIG["port"]=8080
MAP_CONFIG["nom_hote"]="localhost"
MAP_CONFIG["timeout"]=30
# Accéder aux valeurs
echo "Port défini sur : ${MAP_CONFIG["port"]}"
# Itérer sur les clés
for cle in "${!MAP_CONFIG[@]}"; do
echo "Clé : $cle, Valeur : ${MAP_CONFIG[$cle]}"
done
2. Utilisez la Substitution de Processus au Lieu de Fichiers Temporaires
La substitution de processus, écrite sous la forme <(commande) ou >(commande), permet à une commande de traiter la sortie d'une autre commande comme un fichier. Elle est utile lorsqu'un outil attend des chemins de fichiers mais que vos données proviennent de commandes.
Quand Elle est Utile
Par exemple, disons que vous devez comparer deux listes de services générées. diff attend des chemins de fichiers, mais vous n'avez pas besoin d'écrire ces listes dans /tmp.
Sans substitution de processus :
# Inefficace et désordonné
sortie1=$(commande_a)
echo "$sortie1" > /tmp/temp1.txt
sortie2=$(commande_b)
echo "$sortie2" > /tmp/temp2.txt
diff /tmp/temp1.txt /tmp/temp2.txt
rm /tmp/temp1.txt /tmp/temp2.txt
Comparaison Directe Plus Propre
La substitution de processus donne à diff des descripteurs de fichiers temporaires et rend votre script plus simple.
Avec substitution de processus :
# Comparaison propre en une ligne
diff <(commande_a) <(commande_b)
Ce modèle fonctionne bien avec comm, diff et les outils qui nécessitent plusieurs entrées de fichiers.
Variations de Syntaxe :
<(commande)passe la sortie de la commande à un lecteur.>(commande)envoie la sortie écrite dans une autre commande.
3. Ajoutez le Mode Strict et ShellCheck
Les scripts Bash avancés doivent échouer bruyamment lorsque quelque chose d'inattendu se produit. Le mode strict vous aide à détecter les variables manquantes et les pipelines cassés avant qu'ils ne causent des dommages silencieux.
Options Essentielles du Mode Strict
La plupart des scripts d'automatisation devraient commencer par :
set -euo pipefail
-e: Quitter lorsqu'une commande échoue.-u: Traiter les variables non définies comme des erreurs.-o pipefail: Échouer un pipeline si une commande du pipeline échoue.
Exemple :
# Sans pipefail, cela peut sembler réussi car wc se termine proprement
cat fichier.log | grep motif_reussi | wc -l
# Avec set -o pipefail, l'échec de grep fait échouer le pipeline.
Utilisez ShellCheck
ShellCheck détecte les erreurs de guillemets, les expansions dangereuses, le code inaccessible et les problèmes courants de portabilité.
Exécutez-le avant de valider un script :
shellcheck votre_script.sh
Lorsque ShellCheck vous demande de mettre une variable entre guillemets ou d'utiliser "${tableau[@]}", traitez cela comme un vrai bug sauf si vous avez une raison claire de l'ignorer.
4. Capturez la Sortie avec Précaution
La substitution de commande avec $() est utile, mais elle peut cacher des échecs ou mélanger les flux de sortie si vous l'utilisez à la légère.
Capturer à la fois STDOUT et STDERR
Lorsque vous voulez tout journaliser à partir d'une commande, capturez à la fois la sortie standard et l'erreur standard :
# Capturer à la fois stdout et stderr dans la VARIABLE
VARIABLE=$(commande_qui_peut_echouer 2>&1)
# Ignorer à la fois stdout et stderr lorsque vous avez seulement besoin du code de sortie
commande_qui_peut_echouer &> /dev/null
Expansion de Paramètres pour un Nettoyage en Ligne
L'expansion de paramètres peut nettoyer des chaînes sans lancer sed ou awk pour des cas simples.
${variable%motif}supprime le suffixe correspondant le plus court.${variable%%motif}supprime le suffixe correspondant le plus long.${variable#motif}supprime le préfixe correspondant le plus court.${variable##motif}supprime le préfixe correspondant le plus long.
Exemple :
FICHIER="rapport.log.bak"
# Supprimer le suffixe le plus court correspondant à .bak
NOM_PROPRE=${FICHIER%.bak}
echo $NOM_PROPRE # Sortie : rapport.log
# Supprimer tous les suffixes correspondant à *.bak (supprime seulement .bak ici)
NOM_PROPRE_LONG=${FICHIER%%.*}
echo $NOM_PROPRE_LONG # Sortie : rapport
Quand Demander de l'Aide
Demandez à un utilisateur de shell plus expérimenté de revoir votre script lorsqu'il supprime des fichiers, modifie des services de production, gère des secrets ou s'exécute depuis CI. Bash est puissant, mais une petite erreur de guillemets peut affecter chaque fichier correspondant à un motif.
À Retenir
Utilisez des tableaux pour de vraies listes, la substitution de processus pour les sorties de commandes de type fichier, set -euo pipefail pour des échecs plus sûrs, et ShellCheck pour un retour rapide. Ces habitudes rendent les scripts Bash avancés plus faciles à maintenir et beaucoup moins surprenants lors des exécutions d'automatisation.