Scripting bash simple pour automatiser une tâche
Un administrateur ou un analyste de sécurité qui doit répéter dix fois la même série de commandes finit toujours par se dire : « il doit bien y avoir un moyen de faire ça tout seul ». Ce moyen existe, c'est le script. Dans cette dernière leçon du chapitre, vous allez écrire vos premiers scripts bash, simples et utiles, en restant strictement dans votre laboratoire.
Vous connaissez maintenant les commandes de base, les droits, les processus et les journaux. Un script n'est rien d'autre qu'un fichier qui enchaîne ces commandes, avec en plus quelques structures de programmation : variables, conditions, boucles. Pas besoin d'avoir déjà programmé : nous partons de zéro.
Votre premier script
Un script bash est un fichier texte dont la première ligne, appelée shebang, indique quel interpréteur utiliser. Créez le fichier ~/labo-linux/scripts/bonjour.sh avec un éditeur de texte (nano est le plus simple) :
#!/bin/bash
# Mon premier script
echo "Bonjour depuis $(hostname)"
echo "Nous sommes le $(date +%d/%m/%Y)"
Rendez-le exécutable, puis lancez-le :
chmod u+x bonjour.sh
./bonjour.sh
Le ./ signifie « dans le répertoire courant » : par sécurité, Linux ne cherche pas les programmes dans le répertoire où vous vous trouvez. Dans le script, $(commande) remplace l'expression par le résultat de la commande, et tout ce qui suit un # est un commentaire.
Variables et arguments
Une variable stocke une valeur. On l'affecte sans espaces autour du = et on la lit avec $ :
#!/bin/bash
nom="laboratoire"
echo "Bienvenue dans le $nom"
# Arguments passés au script
echo "Le script s'appelle : $0"
echo "Premier argument : $1"
echo "Nombre d'arguments : $#"
Exécuté avec ./script.sh alpha beta, $1 vaut alpha et $# vaut 2. Mettez presque toujours vos variables entre guillemets doubles ("$nom") : sans eux, un nom contenant un espace serait coupé en deux, source d'erreurs fréquentes et, dans un contexte réel, de failles de sécurité.
Conditions : prendre une décision
La structure if teste une condition. Chaque commande renvoie un code de sortie : 0 signifie « réussite », toute autre valeur signale une erreur. Les crochets [ ... ] permettent de tester des fichiers, des nombres ou du texte.
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage : $0 fichier"
exit 1
fi
if [ -f "$1" ]; then
echo "$1 existe et c'est un fichier"
elif [ -d "$1" ]; then
echo "$1 est un répertoire"
else
echo "$1 est introuvable"
fi
Quelques tests utiles : -f (fichier ordinaire existant), -d (répertoire), -z (chaîne vide), -eq (égalité de nombres), = (égalité de textes). Le mot-clé exit 1 termine le script avec un code d'erreur : c'est la façon polie de dire « quelque chose ne va pas ».
Boucles : répéter sans se fatiguer
La boucle for répète des instructions pour chaque élément d'une liste :
#!/bin/bash
for fichier in *.txt; do
echo "Traitement de $fichier : $(wc -l < "$fichier") lignes"
done
for i in 1 2 3; do
echo "Tour numéro $i"
done
La boucle while lit un fichier ligne par ligne, ce qui est précieux pour analyser des journaux :
while read -r ligne; do
echo "Ligne lue : $ligne"
done < liste.txt
Un script utile : sauvegarder un répertoire
Voici un script complet et sûr. Il crée une archive horodatée d'un répertoire dont on lui donne le nom :
#!/bin/bash
# sauvegarde.sh : archive un répertoire dans ~/sauvegardes
set -u # erreur si on utilise une variable non définie
source_dir="${1:-}"
dest_dir="$HOME/sauvegardes"
if [ -z "$source_dir" ] || [ ! -d "$source_dir" ]; then
echo "Usage : $0 repertoire-existant"
exit 1
fi
mkdir -p "$dest_dir"
horodatage=$(date +%Y%m%d-%H%M%S)
nom_archive="$dest_dir/sauvegarde-$(basename "$source_dir")-$horodatage.tar.gz"
tar -czf "$nom_archive" -C "$(dirname "$source_dir")" "$(basename "$source_dir")"
if [ $? -eq 0 ]; then
echo "Archive créée : $nom_archive"
else
echo "Échec de la sauvegarde"
exit 2
fi
Ce script illustre plusieurs bonnes pratiques : vérification des arguments, variables entre guillemets, nom d'archive horodaté (pour ne rien écraser), contrôle du code de sortie de tar avec $?, et messages clairs. Notez que tar -czf crée (c) une archive compressée (z) dans un fichier (f).
Un script de défense : compter les échecs de connexion
Un second exemple, plus orienté sécurité, qui analyse une copie d'un journal d'authentification de votre laboratoire et affiche les adresses qui ont le plus échoué :
#!/bin/bash
# echecs.sh : résume les échecs de connexion SSH d'un fichier de journal
journal="$1"
if [ ! -f "$journal" ]; then
echo "Usage : $0 fichier-journal"
exit 1
fi
echo "Nombre total d'échecs :"
grep -c "Failed password" "$journal"
echo "Adresses les plus fréquentes :"
grep "Failed password" "$journal" \
| grep -oE "from [0-9.]+" \
| sort | uniq -c | sort -rn | head -n 5
Chaque étape du tube a un rôle : grep -c compte, grep -oE extrait seulement la partie « from adresse », sort | uniq -c regroupe et compte les doublons, sort -rn trie du plus fréquent au moins fréquent, head garde les cinq premiers. Cet enchaînement est typique du travail d'un analyste de journaux.
Prudence avec les scripts. Un script s'exécute avec les droits de celui qui le lance : un script copié sans être lu, lancé avec sudo, peut tout supprimer ou installer n'importe quoi. Lisez toujours un script avant de l'exécuter, ne lancez jamais « à l'aveugle » un script trouvé sur Internet, et testez les vôtres d'abord sur des données de test dans votre laboratoire. Ne mettez jamais de mot de passe en clair dans un script.
Planifier l'exécution
Une fois un script au point, on peut le faire tourner automatiquement avec cron. La commande crontab -e ouvre votre table de tâches ; une ligne comme 30 2 * * * /home/antoine/labo-linux/scripts/sauvegarde.sh /home/antoine/labo-linux lance la sauvegarde chaque nuit à 2 h 30 (minute, heure, jour du mois, mois, jour de la semaine, commande). Les chemins complets sont indispensables, car cron n'a pas le même environnement que votre terminal.
À vous de jouer
Exercice 1. Créez le script sauvegarde.sh ci-dessus, rendez-le exécutable et testez-le sur votre répertoire ~/labo-linux/rapports. Vérifiez l'archive avec tar -tzf.
Exercice 2. Créez un faux fichier de journal faux.log d'une dizaine de lignes de type « Failed password for invite from 10.10.10.10 port … ssh2 » (en variant l'adresse entre 10.10.10.10 et 10.10.10.20) puis lancez echecs.sh dessus.
Exercice 3. Écrivez un script verif.sh qui prend un nom de service en argument, affiche « actif » ou « inactif » grâce à systemctl is-active, et quitte avec un code d'erreur si aucun argument n'est fourni.
Voir une solution
Exercice 3 :
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage : $0 nom-du-service"
exit 1
fi
if systemctl is-active --quiet "$1"; then
echo "Le service $1 est actif"
else
echo "Le service $1 est inactif"
fi
La commande systemctl is-active --quiet ne produit pas de sortie mais renvoie 0 si le service est actif, ce qui convient parfaitement à un if. Pour l'exercice 1, la liste donnée par tar -tzf doit contenir les fichiers de rapports ; pour l'exercice 2, le script affiche le total des lignes « Failed password » et les deux adresses les plus fréquentes.
À retenir
- Un script bash est un fichier texte avec un shebang (
#!/bin/bash), rendu exécutable avecchmod u+xet lancé avec./. - Variables, arguments (
$1,$#), conditions (if) et boucles (for,while) suffisent à automatiser de nombreuses tâches. - Les bonnes pratiques : variables entre guillemets, vérification des arguments, codes de sortie, horodatage, messages clairs.
- Un enchaînement
grep | sort | uniq -c | sort -rnrésume rapidement un journal. - On lit toujours un script avant de l'exécuter, on n'y met jamais de secret en clair, et on teste dans le laboratoire.
Vous venez de terminer l'exploration de Linux, le système sur lequel repose une grande partie des serveurs et des outils de sécurité. Mais en entreprise, un autre acteur domine les postes de travail : Windows. Chapitre suivant : son architecture, Active Directory et les journaux d'événements.