LinuxBashAutomatisationDevOps

Bash scripting : automatiser les tâches d'administration Linux

24 août 2026 · Sphinx-Digital

Bash est omniprésent : déploiements, cron jobs, scripts d’init, hooks Git, pipelines CI. Un script Bash mal écrit fonctionne jusqu’au jour où il détruit quelque chose en production. Voici les bases pour écrire des scripts fiables.

Le shebang et les options de sécurité

Chaque script commence par deux lignes qui changent tout :

#!/usr/bin/env bash
set -euo pipefail
  • set -e : arrête le script dès qu’une commande retourne un code non-zéro
  • 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

Sans ces options, un script peut silencieusement ignorer des erreurs et continuer à s’exécuter dans un état incohérent.

Variables : typage et portée

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

# Constantes en majuscules
readonly DEPLOY_DIR="/opt/myapp"
readonly LOG_FILE="/var/log/deploy.log"
readonly TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Variables locales dans les fonctions
process_file() {
    local file="$1"          # local = scope limité à la fonction
    local basename
    basename=$(basename "$file")
    echo "Traitement : $basename"
}

# Valeur par défaut si variable non définie
ENVIRONMENT="${ENVIRONMENT:-staging}"
MAX_RETRIES="${MAX_RETRIES:-3}"

Toujours mettre les variables entre guillemets doubles ("$var") pour éviter les problèmes avec les espaces et les caractères spéciaux.

Fonctions : structurer le code

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

# Logging standardisé
log()   { echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO  $*" | tee -a "$LOG_FILE"; }
warn()  { echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARN  $*" | tee -a "$LOG_FILE" >&2; }
error() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR $*" | tee -a "$LOG_FILE" >&2; exit 1; }

check_prerequisites() {
    local missing=0
    for cmd in docker kubectl helm; do
        if ! command -v "$cmd" &>/dev/null; then
            warn "Commande manquante : $cmd"
            missing=$((missing + 1))
        fi
    done
    [[ $missing -eq 0 ]] || error "Prérequis manquants. Abandon."
}

deploy_application() {
    local image="$1"
    local namespace="${2:-default}"

    log "Déploiement de $image dans $namespace"
    kubectl set image deployment/myapp app="$image" -n "$namespace"
    kubectl rollout status deployment/myapp -n "$namespace" --timeout=5m
    log "Déploiement terminé"
}

Gestion des erreurs et nettoyage

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

TMPDIR=$(mktemp -d)

# Cleanup automatique à la sortie du script (succès ou erreur)
cleanup() {
    local exit_code=$?
    rm -rf "$TMPDIR"
    if [[ $exit_code -ne 0 ]]; then
        error "Le script a échoué avec le code $exit_code"
    fi
}
trap cleanup EXIT

# Traiter les signaux (Ctrl+C, kill)
trap 'warn "Interruption reçue"; exit 130' INT TERM

# Retry automatique pour les opérations réseau
retry() {
    local max_attempts="$1"
    local delay="$2"
    shift 2
    local attempt=1

    until "$@"; do
        if [[ $attempt -ge $max_attempts ]]; then
            error "Échec après $max_attempts tentatives : $*"
        fi
        warn "Tentative $attempt/$max_attempts échouée, retry dans ${delay}s"
        sleep "$delay"
        attempt=$((attempt + 1))
    done
}

# Utilisation
retry 3 5 curl -sf https://api.example.com/health

Boucles et traitement de fichiers

# Itérer sur des fichiers — toujours avec find, jamais ls
while IFS= read -r -d '' file; do
    log "Traitement : $file"
    process_file "$file"
done < <(find /data -name "*.csv" -newer /tmp/last_run -print0)

# Lire un fichier ligne par ligne
while IFS= read -r line; do
    [[ -z "$line" || "$line" == \#* ]] && continue  # ignorer vides et commentaires
    echo "Ligne : $line"
done < config.txt

# Tableau de serveurs
declare -a SERVERS=("web01" "web02" "web03" "db01")
for server in "${SERVERS[@]}"; do
    ssh -o ConnectTimeout=5 "$server" "systemctl status myapp" || warn "$server : non joignable"
done

Validation des arguments

usage() {
    cat << USAGE
Usage: $(basename "$0") [OPTIONS] <environment>

OPTIONS:
  -i, --image IMAGE    Image Docker à déployer
  -n, --dry-run        Simuler sans effectuer de changements
  -h, --help           Afficher cette aide

EXEMPLES:
  $(basename "$0") production -i myapp:1.2.3
  $(basename "$0") staging --dry-run
USAGE
    exit 1
}

# Parser les arguments
DRY_RUN=false
IMAGE=""
ENVIRONMENT=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        -i|--image)   IMAGE="$2";    shift 2 ;;
        -n|--dry-run) DRY_RUN=true;  shift   ;;
        -h|--help)    usage                   ;;
        -*)           error "Option inconnue : $1" ;;
        *)            ENVIRONMENT="$1"; shift  ;;
    esac
done

[[ -n "$ENVIRONMENT" ]] || error "L'environnement est requis"
[[ -n "$IMAGE" ]]       || error "L'image Docker est requise"
[[ "$ENVIRONMENT" =~ ^(staging|production)$ ]] || error "Environnement invalide : $ENVIRONMENT"

Notre formation Linux couvre Bash scripting en profondeur avec des ateliers sur des cas réels d’administration système.