DevOpsFacile
AccueilParcours de formationCertificationsModulesCheat SheetÀ Propos
DevOpsFacile

Une plateforme d'apprentissage complète pour maîtriser les pratiques DevOps modernes, du débutant à l'expert.

contact@devopsfacile.fr

Formation

  • Parcours de formation
  • Modules

Informations

  • À Propos
  • Conditions d'utilisation
  • Confidentialité
  • Mentions légales

© 2026 DevOps Facile. Tous droits réservés.

Fait avec pour la communauté DevOps

ModulesScripting Bash et administration système Linux09 - Scripts Bash : variables, conditions et boucles

Détails

  • 35 minutes
  • Avancé

Objectifs

  • Écrire un script Bash robuste avec set -euo pipefail
  • Utiliser les variables, arguments et substitutions de commandes
  • Implémenter des conditions avec if/case et des boucles for/while
  • Valider les arguments et gérer les erreurs proprement
Module Scripting Bash et administration système Linux

Exercice 09 : Scripts Bash : variables, conditions et boucles

🎯 Objectifs

À la fin de cet exercice, vous serez capable de :

  • ✅ Démarrer chaque script avec set -euo pipefail (fail-safe)
  • ✅ Utiliser les variables positionnelles $1, $2, $#, $@
  • ✅ Écrire des conditions if/elif/else avec tests de fichiers et de chaînes
  • ✅ Utiliser case pour les alternatives multiples
  • ✅ Itérer avec for, while et until

Durée estimée : 35 minutes

Difficulté : ⭐⭐⭐☆☆ (Avancé)

Prérequis : Maîtrise du terminal Linux, avoir complété les modules débutant et intermédiaire


📖 Contexte

Un script Bash sans structure est fragile : une commande qui échoue silencieusement, une variable non définie qui prend une valeur vide, et c'est tout le script qui part en vrille. Les trois lignes magiques set -euo pipefail transforment un script fragile en script qui échoue vite et clairement.


📋 Énoncé

Écrivez une suite de scripts Bash de complexité croissante pour automatiser des tâches d'administration système.


🧭 Déroulement de l'exercice

Tâche 1 : Le script fail-safe de base

Créez 01-structure.sh qui montre la structure minimale d'un script robuste :

bash
cat > 01-structure.sh << 'EOF'
#!/usr/bin/env bash
# Description : Template de script Bash robuste
# Usage : ./01-structure.sh <nom_utilisateur>

# FONDAMENTAL : ces 3 options rendent le script fail-safe
set -e  # Exit immédiatement si une commande échoue
set -u  # Erreur si une variable non définie est utilisée
set -o pipefail  # Un pipe échoue si n'importe quelle commande du pipe échoue
# Raccourci : set -euo pipefail

# Variables avec valeurs par défaut
NOM_SCRIPT="$(basename "$0")"
UTILISATEUR="${1:-}"  # Vide si pas d'argument

# Validation des arguments
if [[ -z "$UTILISATEUR" ]]; then
  echo "Usage: $NOM_SCRIPT <nom_utilisateur>" >&2
  exit 1
fi

if [[ "$UTILISATEUR" =~ [^a-zA-Z0-9_-] ]]; then
  echo "Erreur: nom d'utilisateur invalide '$UTILISATEUR'" >&2
  exit 2
fi

echo "Bonjour, $UTILISATEUR !"
echo "Date : $(date '+%Y-%m-%d %H:%M:%S')"
echo "Répertoire courant : $PWD"
EOF
chmod +x 01-structure.sh

Test :

bash
./01-structure.sh          # Doit afficher le message d'usage et exit 1
./01-structure.sh alice    # Doit afficher "Bonjour, alice !"
./01-structure.sh "bad name"  # Doit rejeter le nom invalide
echo "Code de sortie : $?"

Vérification : Sans argument, le script retourne le code 1 et affiche le message d'usage sur stderr.


Tâche 2 : Conditions et tests de fichiers

bash
cat > 02-conditions.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

CIBLE="${1:-}"

if [[ -z "$CIBLE" ]]; then
  echo "Usage: $0 <chemin>" >&2
  exit 1
fi

# Tests de fichiers
if [[ -f "$CIBLE" ]]; then
  TAILLE=$(du -h "$CIBLE" | cut -f1)
  echo "Fichier normal : $CIBLE (taille: $TAILLE)"

  # Droits
  if [[ -r "$CIBLE" ]]; then echo "  → Lisible"; fi
  if [[ -w "$CIBLE" ]]; then echo "  → Modifiable"; fi
  if [[ -x "$CIBLE" ]]; then echo "  → Exécutable"; fi

elif [[ -d "$CIBLE" ]]; then
  NB_FICHIERS=$(find "$CIBLE" -maxdepth 1 -type f | wc -l)
  echo "Répertoire : $CIBLE ($NB_FICHIERS fichiers directs)"

elif [[ -L "$CIBLE" ]]; then
  CIBLE_LIEN=$(readlink -f "$CIBLE")
  echo "Lien symbolique : $CIBLE → $CIBLE_LIEN"

else
  echo "Chemin inexistant ou type inconnu : $CIBLE"
  exit 3
fi

# Case pour l'extension
if [[ -f "$CIBLE" ]]; then
  EXTENSION="${CIBLE##*.}"
  case "$EXTENSION" in
    sh|bash)   echo "  Type: script shell" ;;
    py)        echo "  Type: script Python" ;;
    json|yaml) echo "  Type: fichier de configuration" ;;
    log)       echo "  Type: fichier de log" ;;
    *)         echo "  Type: extension inconnue (.$EXTENSION)" ;;
  esac
fi
EOF
chmod +x 02-conditions.sh
./02-conditions.sh /etc/hosts
./02-conditions.sh /tmp
./02-conditions.sh 01-structure.sh

Tâche 3 : Boucles for et while

bash
cat > 03-boucles.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

echo "=== Boucle for sur des valeurs ==="
SERVICES=("nginx" "ssh" "cron" "docker")
for SERVICE in "${SERVICES[@]}"; do
  # Vérifier si le service est actif (sans planter si absent)
  if systemctl is-active --quiet "$SERVICE" 2>/dev/null; then
    echo "  ✅ $SERVICE : actif"
  else
    echo "  ❌ $SERVICE : inactif ou absent"
  fi
done

echo ""
echo "=== Boucle for sur des fichiers ==="
COMPTEUR=0
for FICHIER in /etc/*.conf; do
  [[ -f "$FICHIER" ]] || continue  # Ignorer si pas un fichier normal
  COMPTEUR=$((COMPTEUR + 1))
done
echo "Fichiers .conf dans /etc : $COMPTEUR"

echo ""
echo "=== Boucle while avec compteur ==="
TENTATIVE=1
MAX_TENTATIVES=3
while [[ $TENTATIVE -le $MAX_TENTATIVES ]]; do
  echo "  Tentative $TENTATIVE/$MAX_TENTATIVES..."
  # Simuler une opération (succès à la tentative 2)
  if [[ $TENTATIVE -eq 2 ]]; then
    echo "  ✅ Succès à la tentative $TENTATIVE"
    break
  fi
  TENTATIVE=$((TENTATIVE + 1))
  sleep 0.1  # Pause courte entre les tentatives
done

if [[ $TENTATIVE -gt $MAX_TENTATIVES ]]; then
  echo "  ❌ Echec après $MAX_TENTATIVES tentatives"
  exit 1
fi
EOF
chmod +x 03-boucles.sh
./03-boucles.sh

Vérification : Le script affiche l'état des services, le nombre de .conf, et simule une boucle de retry.


Tâche 4 : Script de surveillance des disques avec alertes

Assemblez les acquis dans un script utile :

bash
cat > 04-surveiller-disques.sh << 'EOF'
#!/usr/bin/env bash
# Surveille l'utilisation des disques et alerte si seuil dépassé
set -euo pipefail

SEUIL_ALERTE="${1:-80}"  # Seuil par défaut : 80%
LOG_FILE="${2:-/tmp/disk-alert.log}"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
ALERTES=0

# Valider que le seuil est un nombre entre 1 et 99
if ! [[ "$SEUIL_ALERTE" =~ ^[0-9]+$ ]] || [[ "$SEUIL_ALERTE" -lt 1 || "$SEUIL_ALERTE" -gt 99 ]]; then
  echo "Erreur: le seuil doit être un nombre entre 1 et 99" >&2
  exit 1
fi

echo "[$DATE] Vérification des disques (seuil: ${SEUIL_ALERTE}%)" | tee -a "$LOG_FILE"
echo "---" | tee -a "$LOG_FILE"

# Lire la sortie de df ligne par ligne
while IFS= read -r LIGNE; do
  # Extraire le pourcentage et le point de montage
  POURCENTAGE=$(echo "$LIGNE" | awk '{print $5}' | tr -d '%')
  MONTAGE=$(echo "$LIGNE" | awk '{print $6}')

  # Ignorer les en-têtes et les systèmes de fichiers virtuels
  [[ "$POURCENTAGE" =~ ^[0-9]+$ ]] || continue
  [[ "$MONTAGE" =~ ^/(dev|proc|sys|run) ]] && continue

  if [[ "$POURCENTAGE" -ge "$SEUIL_ALERTE" ]]; then
    MSG="⚠️  ALERTE: $MONTAGE à ${POURCENTAGE}% (seuil: ${SEUIL_ALERTE}%)"
    echo "$MSG" | tee -a "$LOG_FILE"
    ALERTES=$((ALERTES + 1))
  else
    echo "  ✅ $MONTAGE : ${POURCENTAGE}%" | tee -a "$LOG_FILE"
  fi

done < <(df -h | tail -n +2)

echo "---" | tee -a "$LOG_FILE"
echo "Bilan : $ALERTES partition(s) en alerte" | tee -a "$LOG_FILE"

# Code de sortie non-nul si des alertes existent (utile pour le monitoring)
[[ $ALERTES -eq 0 ]]
EOF
chmod +x 04-surveiller-disques.sh

# Tests
./04-surveiller-disques.sh 1    # Seuil très bas = beaucoup d'alertes
./04-surveiller-disques.sh 95   # Seuil très haut = probablement aucune alerte
echo "Code de sortie : $?"

✅ Vérification du résultat

  • ./01-structure.sh sans argument retourne exit code 1
  • ./01-structure.sh alice affiche "Bonjour, alice !"
  • ./02-conditions.sh /etc/hosts identifie correctement le type de fichier
  • ./03-boucles.sh affiche l'état des services et le bilan disques
  • ./04-surveiller-disques.sh 1 génère des alertes et exit code 1

💡 À retenir

Les 3 options indispensables :

OptionEffet
set -eLe script s'arrête à la première commande qui échoue
set -uErreur si une variable non définie est utilisée
set -o pipefailcmd1 | cmd2 échoue si cmd1 échoue (pas seulement cmd2)

Tests de fichiers courants :

  • -f : fichier normal, -d : répertoire, -L : lien symbolique
  • -r / -w / -x : lisible / modifiable / exécutable
  • -z : chaîne vide, -n : chaîne non vide

✨ Solution Complète

bash
#!/usr/bin/env bash
set -euo pipefail

# Validation
[[ $# -ge 1 ]] || { echo "Usage: $0 <arg>" >&2; exit 1; }

# Variables
NOM="${1}"
VALEUR="${2:-valeur_par_defaut}"

# Condition
if [[ -f "$NOM" ]]; then
  echo "C'est un fichier"
elif [[ -d "$NOM" ]]; then
  echo "C'est un répertoire"
fi

# Boucle
for ITEM in un deux trois; do
  echo "$ITEM"
done
Retour au module

Sur cette page

  • 🎯 Objectifs
  • 📖 Contexte
  • 📋 Énoncé
  • 🧭 Déroulement de l'exercice
  • Tâche 1 : Le script fail-safe de base
  • Tâche 2 : Conditions et tests de fichiers
  • Tâche 3 : Boucles for et while
  • Tâche 4 : Script de surveillance des disques avec alertes
  • ✅ Vérification du résultat
  • 💡 À retenir
  • ✨ Solution Complète