📜 Scripting Bash — Automatisation système

Bloc 2 Module 2.2 BTS SIO SISR
FormationBTS SIO option SISR — IRIS Mediaschool
BlocB2 — Administration Systèmes & Réseaux
ModuleM2.2 — Administration Linux
PrérequisMaîtrise du shell Linux (C2.2.1)

🎯 Objectifs

  • Écrire et exécuter des scripts Bash
  • Maîtriser les variables, les conditions et les boucles
  • Créer des fonctions réutilisables
  • Manipuler du texte avec grep, sed, awk et les expressions régulières
  • Appliquer les bonnes pratiques de scripting
  • Automatiser des tâches d'administration courantes

📖 Shebang et exécution de scripts

Un script Bash est un fichier texte contenant une suite de commandes. La première ligne, le shebang, indique l'interpréteur à utiliser :

#!/bin/bash
# Mon premier script
echo "Bonjour, monde !"

Pour rendre un script exécutable et le lancer :

# Rendre exécutable
chmod +x mon_script.sh

# Exécuter
./mon_script.sh

# Ou explicitement avec bash
bash mon_script.sh
💡 Astuce

Utilisez #!/usr/bin/env bash plutôt que #!/bin/bash pour une meilleure portabilité entre systèmes, car le chemin de bash peut varier.

📖 Variables, types et expansion

En Bash, les variables ne sont pas typées — tout est traité comme une chaîne de caractères :

#!/bin/bash

# Affectation (pas d'espace autour du =)
nom="Alice"
age=25
repertoire="/var/log"

# Utilisation avec $
echo "Bonjour $nom, vous avez $age ans"

# Expansion avec accolades (recommandé)
echo "Fichier : ${nom}_backup.tar.gz"

# Substitution de commande
date_actuelle=$(date +%Y-%m-%d)
nb_fichiers=$(ls /tmp | wc -l)
echo "Date : $date_actuelle — Fichiers dans /tmp : $nb_fichiers"

# Variables en lecture seule
readonly VERSION="1.0"

# Variables de calcul
resultat=$((10 + 5))
echo "Résultat : $resultat"
⚠️ Attention

Pas d'espace autour du = lors de l'affectation ! nom = "Alice" provoquera une erreur (Bash interprète nom comme une commande).

📖 Entrée utilisateur et arguments

#!/bin/bash

# Lire une entrée utilisateur
read -p "Entrez votre nom : " nom
echo "Bonjour, $nom !"

# Lire un mot de passe (sans affichage)
read -sp "Mot de passe : " mdp
echo ""

# Arguments du script
echo "Nom du script : $0"
echo "Premier argument : $1"
echo "Deuxième argument : $2"
echo "Tous les arguments : $@"
echo "Nombre d'arguments : $#"
echo "Code retour dernière commande : $?"
VariableDescription
$0Nom du script
$1, $2, …Arguments positionnels
$@Tous les arguments (chacun entre guillemets)
$*Tous les arguments (comme une seule chaîne)
$#Nombre d'arguments
$?Code retour de la dernière commande (0 = succès)
$$PID du script en cours

📖 Structures conditionnelles

#!/bin/bash

# Structure if/elif/else
if [[ $# -eq 0 ]]; then
    echo "Aucun argument fourni"
    exit 1
elif [[ $1 == "start" ]]; then
    echo "Démarrage du service..."
elif [[ $1 == "stop" ]]; then
    echo "Arrêt du service..."
else
    echo "Usage : $0 {start|stop}"
    exit 1
fi

# Opérateur ternaire avec &&  et ||
[[ -f "/etc/hosts" ]] && echo "Le fichier existe" || echo "Le fichier n'existe pas"

Comparaisons

TypeOpérateurDescription
Numérique-eqÉgal
-neDifférent
-lt, -leInférieur (strict / ou égal)
-gt, -geSupérieur (strict / ou égal)
Chaîne==Égale
!=Différente
-z, -nVide / Non vide
Fichier-fEst un fichier régulier
-dEst un répertoire
-eExiste
-rEst lisible
-wEst modifiable
-xEst exécutable
💡 Astuce

Préférez [[ ]] à [ ] (test). La syntaxe double crochet est spécifique à Bash et offre des fonctionnalités supplémentaires : pas de word splitting, support des expressions régulières avec =~, et opérateurs && / || à l'intérieur.

📖 Boucles

#!/bin/bash

# Boucle for classique
for fichier in /var/log/*.log; do
    echo "Traitement de $fichier"
    wc -l "$fichier"
done

# Boucle for avec séquence
for i in {1..10}; do
    echo "Itération $i"
done

# Boucle for de style C
for ((i = 0; i < 5; i++)); do
    echo "Index : $i"
done

# Boucle while
compteur=0
while [[ $compteur -lt 5 ]]; do
    echo "Compteur : $compteur"
    ((compteur++))
done

# Boucle while pour lire un fichier ligne par ligne
while IFS= read -r ligne; do
    echo "Ligne : $ligne"
done < /etc/hostname

# Boucle until (s'exécute tant que la condition est fausse)
until ping -c 1 -W 1 8.8.8.8 &>/dev/null; do
    echo "En attente de connexion réseau..."
    sleep 2
done
echo "Connexion établie !"

📖 Fonctions et portée des variables

#!/bin/bash

# Déclaration d'une fonction
verifier_service() {
    local service_name="$1"   # Variable locale

    if systemctl is-active --quiet "$service_name"; then
        echo "[OK] $service_name est actif"
        return 0
    else
        echo "[ERREUR] $service_name est inactif"
        return 1
    fi
}

# Appel de la fonction
verifier_service "nginx"
verifier_service "ssh"

# Récupérer le code retour
if verifier_service "apache2"; then
    echo "Apache fonctionne correctement"
fi
💡 Astuce

Utilisez local pour déclarer des variables locales dans les fonctions. Sans local, les variables sont globales et peuvent interférer avec le reste du script.

📖 Manipulation de texte

OutilUsageExemple
grepRechercher un motifgrep -i "error" /var/log/syslog
sedRemplacer du textesed 's/ancien/nouveau/g' fichier
awkTraiter des colonnesawk '{print $1, $3}' fichier
cutExtraire des champscut -d: -f1 /etc/passwd
sortTriersort -rn fichier
uniqDédoublonner (après tri)sort fichier | uniq -c
wcCompter lignes/mots/octetswc -l fichier
# Exemple combiné : top 5 des utilisateurs avec le plus de processus
ps aux | awk '{print $1}' | sort | uniq -c | sort -rn | head -5

# Remplacer une IP dans un fichier de configuration
sed -i 's/192\.168\.1\.10/10.0.0.50/g' /etc/myapp/config.conf

# Extraire les noms d'utilisateurs depuis /etc/passwd
awk -F: '{print $1, $3, $7}' /etc/passwd | column -t

📖 Expressions régulières

Les expressions régulières (regex) permettent de définir des motifs de recherche complexes :

MotifSignificationExemple
.N'importe quel caractèrea.c → abc, aXc
*0 ou plusieurs fois l'élément précédentab*c → ac, abc, abbc
+1 ou plusieurs fois (regex étendue)ab+c → abc, abbc
?0 ou 1 fois (regex étendue)ab?c → ac, abc
^Début de ligne^root
$Fin de lignebash$
[abc]Un caractère parmi a, b ou c[0-9]+
\dUn chiffre (équivalent [0-9])
# grep avec regex basique
grep '^root' /etc/passwd

# grep avec regex étendue (-E)
grep -E '^[a-z]+:[x*]:0:' /etc/passwd

# Valider un format d'adresse IP
if [[ "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
    echo "Format IP valide"
fi

📖 Exemples de scripts utiles

Backup automatisé

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/backup"
SOURCE="/var/www"
DATE=$(date +%Y-%m-%d_%H-%M)
ARCHIVE="${BACKUP_DIR}/www_${DATE}.tar.gz"

mkdir -p "$BACKUP_DIR"
tar -czf "$ARCHIVE" "$SOURCE"

# Supprimer les backups de plus de 30 jours
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete

echo "[$(date)] Backup terminé : $ARCHIVE"

Surveillance de disque

#!/bin/bash
set -euo pipefail

SEUIL=80

df -h --output=pcent,target | tail -n +2 | while read -r usage mount; do
    pourcent=${usage%\%}
    if [[ $pourcent -ge $SEUIL ]]; then
        echo "ALERTE : $mount utilise ${pourcent}% de l'espace disque"
        # Envoyer un mail ou une notification
    fi
done

Gestion d'utilisateurs en masse

#!/bin/bash
set -euo pipefail

# Fichier CSV : prenom,nom,groupe
FICHIER_USERS="utilisateurs.csv"

while IFS=',' read -r prenom nom groupe; do
    login="${prenom,,}.${nom,,}"   # Minuscules
    if ! id "$login" &>/dev/null; then
        useradd -m -s /bin/bash -G "$groupe" "$login"
        echo "${login}:ChangeMe123!" | chpasswd
        echo "[CRÉÉ] $login (groupe: $groupe)"
    else
        echo "[EXISTE] $login"
    fi
done < "$FICHIER_USERS"

📖 Bonnes pratiques

  • Toujours commencer par set -euo pipefail :
#!/bin/bash
set -euo pipefail
# -e : arrêter le script à la première erreur
# -u : erreur si une variable non définie est utilisée
# -o pipefail : considérer les erreurs dans les pipes
  • Commenter le code : expliquer le « pourquoi », pas le « quoi »
  • Utiliser des guillemets autour des variables : "$var" pour éviter le word splitting
  • Logging : enregistrer les actions dans un fichier de log
  • Vérifier les prérequis : tester l'existence des commandes et fichiers nécessaires
  • Utiliser des fonctions pour structurer et réutiliser le code
  • Tester avec shellcheck : outil d'analyse statique pour détecter les erreurs
# Installer et utiliser shellcheck
sudo apt install shellcheck
shellcheck mon_script.sh

📝 QCM — Testez vos connaissances

  1. Quelle ligne commence un script Bash ?
  2. Comment rendre un script exécutable ?
  3. Quelle syntaxe utilise-t-on pour une condition en Bash ?
  4. Comment parcourir une liste d'éléments en Bash ?
  5. Que représente $1 dans un script Bash ?
  6. Comment capturer la sortie d'une commande dans une variable ?
📝 Afficher les corrections
  1. #!/bin/bash (shebang) — Le shebang #!/bin/bash indique au système d'utiliser Bash pour interpréter le script.
  2. chmod +x script.sh — La commande chmod +x ajoute le droit d'exécution au fichier script.
  3. if [ condition ]; then ... fi — La structure if/then/elif/else/fi permet les tests conditionnels en Bash.
  4. for item in liste; do ... done — La boucle for itère sur une liste de valeurs, un fichier ou le résultat d'une commande.
  5. Le premier argument passé au script — Les variables $1, $2, $3... sont les arguments positionnels, $0 est le nom du script, $# le nombre d'arguments.
  6. variable=$(commande) — La substitution de commande $() exécute la commande et stocke sa sortie dans la variable.
💡 À retenir

Le scripting Bash est la clé de l'automatisation sous Linux. Maîtrisez les variables, conditions, boucles et fonctions. Utilisez grep, sed et awk pour manipuler du texte. Appliquez toujours set -euo pipefail et vérifiez vos scripts avec shellcheck.

← Cours précédent Cours suivant →