Mini-test 8
Gerer les erreurs, capturer les sorties, survivre aux pannes
9 questions ciblees
Cliquez Voir la solution sur chaque slide
Question 1 / 9 > ecraser
/var/log/etat-disque.txt
qui contient l'utilisation actuelle du disque (la commande df -h
produit ce qu'on veut). Le fichier doit contenir seulement
le plus recent : a chaque execution, on ecrase le precedent.
Commande complete :
> redirige la sortie vers un fichier en l'ecrasant.
Format : commande > fichier.
NAME
df - report file system disk space usage
SYNOPSIS
df [OPTION...] [FILE...]
DESCRIPTION
Affiche l'espace disque utilise et disponible sur les systemes de
fichiers contenant chaque argument FILE (par defaut : tous montes).
OPTIONS
-h, --human-readable
tailles lisibles : 1.0K, 2.3M, 5.7G (puissances de 1024)
-H, --si
comme -h, mais puissances de 1000 (1.0KB = 1000 octets)
-T, --print-type
afficher le type de systeme de fichiers (ext4, xfs...)
-i, --inodes
afficher les inodes utilises au lieu des octets
-a, --all
inclure les pseudo, dummy, dupliques systemes de fichiers
--total
ajouter une ligne de total general
-x TYPE
exclure le type de systeme de fichiers TYPE
EXEMPLES
# Format lisible humain
df -h
# Avec type de systeme
df -hT
# Inodes au lieu d'octets
df -i
# Snapshot dans un fichier (la question Q1 !)
df -h > /var/log/etat-disque.txt
# Filtrer un point de montage precis
df -h /home
df -h > /var/log/etat-disque.txt
Effet :
Variantes :
ps aux > /var/log/processus.txt # snapshot des process free -h > /var/log/memoire.txt # snapshot memoire systemctl status ircd-hybrid > etat.txt # statut a un instant
Question 2 / 9 >> ajouter
/var/log/historique-sauvegardes.log
sans effacer les precedentes.
Le message doit dire "Sauvegarde OK le ..." avec la date du jour.
Exemple de ce que devrait contenir le journal apres 3 jours :
Commande complete :
>> ajoute a la fin du fichier (au lieu d'ecraser).
Pour la date, $(date) entoure de guillemets dans la chaine
echo. Format : echo "texte $(date)" >> fichier.
echo "Sauvegarde OK le $(date)" >> /var/log/historique-sauvegardes.log
Difference avec Q1 :
> : ecrase (un seul etat present)>> : ajoute (historique cumulatif)Variante avec date formattee :
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sauvegarde OK" \
>> /var/log/historique-sauvegardes.log
Question 3 / 9 2 alternatives en bash
try/catch pour gerer
les erreurs. En bash, on a 2 facons originales de le
faire sur une seule ligne, sans bloc, qui peuvent surprendre quand on
vient d'un autre langage.
| Methode | Forme | Logique |
|---|---|---|
| 1. Reagir a l'echec | cmd || echo "erreur" | Si le code de sortie est non-nul, executer la suite |
| 2. Capturer le stderr | cmd 2> erreur.txt | Detourner le flux d'erreurs (stderr, fd 2) vers un fichier |
"Erreur de sauvegarde" si backup-ircd.sh echoue :backup-ircd.sh dans /var/log/erreurs.txt :|| est un operateur logique : il declenche la commande suivante
SI la premiere echoue (code de sortie != 0). 2> est une
redirection : il deroute le canal stderr (file descriptor 2) vers un
fichier. Les deux sont independantes - on peut les combiner (Q4) ou
en utiliser une seule.
Methode 1 - Reagir a l'echec :
backup-ircd.sh || echo "Erreur de sauvegarde"
backup-ircd.sh reussit (code 0) : rienbackup-ircd.sh echoue (code non-nul) : on affiche "Erreur de sauvegarde"Methode 2 - Capturer le stderr :
backup-ircd.sh 2> /var/log/erreurs.txt
stderr partent dans le fichier2>>)Pour un programmeur habitue au try/catch :
// JS/Java
try { backup(); } catch (e) { console.log("Erreur"); }
// Bash methode 1
backup-ircd.sh || echo "Erreur"
// La methode 2 est differente : on n'essaie pas de "rattraper", on
// se contente de DETOURNER les messages d'erreur dans un fichier.
Dans la prochaine question (Q4), on combinera les deux pour avoir le meilleur des deux mondes.
Question 4 / 9 echec + stderr dans un log
backup-ircd.sh. Vous voulez :
(1) capturer les erreurs (stderr) dans /var/log/blabla-erreur.txt, et
(2) si la commande echoue au total, afficher "blabla erreur" dans le terminal.
Donnez la commande complete (une seule ligne) :
2> (rediriger stderr vers un fichier) et
|| echo "..." (afficher si echec). Ordre : la redirection
s'applique a la commande, le || teste le code de sortie de
l'ensemble.
backup-ircd.sh 2> /var/log/blabla-erreur.txt || echo "blabla erreur"
Decomposition :
2> : envoie stderr (descriptor 2) dans le fichier (en ecrasant a chaque execution)|| : declenche la suite si la commande echoue (code de sortie non-nul)echo "..." : message visible dans le terminalPour garder l'historique des erreurs (append) :
backup-ircd.sh 2>> /var/log/blabla-erreur.txt || echo "blabla erreur"
Pour aussi stopper le script :
backup-ircd.sh 2> /var/log/blabla-erreur.txt || { echo "blabla erreur"; exit 1; }
Question 5 / 9 commande silencieuse + erreur
cp /etc/ircd-hybrid.conf /backup/ est silencieuse
quand tout va bien. Si elle echoue (fichier manquant, permissions),
elle affiche un message sur stderr.
cp echoue, ajouter "Echec copie" a /var/log/erreurs.log (sans effacer le precedent) :cp (stderr) dans le meme fichier :2>> pour rediriger le stderr de la commande
vers le log, et (2) || echo "..." >> pour ajouter notre
propre message daté en cas d'echec.
a) Notre message seulement :
cp /etc/ircd-hybrid.conf /backup/ \
|| echo "Echec copie" >> /var/log/erreurs.log
b) Notre message + le stderr natif :
cp /etc/ircd-hybrid.conf /backup/ 2>> /var/log/erreurs.log \
|| echo "Echec copie le $(date)" >> /var/log/erreurs.log
Le 2>> capture le stderr de cp (avant le ||),
et le echo apres le || n'est execute que si cp a
echoue. Resultat : si cp reussit, rien dans le log ; si cp echoue,
deux lignes (message natif + notre message date).
Question 6 / 9 || pour gerer un echec
cp echouecp /var/lib/ircd-hybrid/data /var/backups/.
Vous voulez (a) afficher un message d'erreur, puis (b) quitter le script.
"Erreur de copie" si cp echoue :|| execute la commande suivante seulement si la premiere echoue.
Pour grouper plusieurs commandes : { ... ; } avec espace et
point-virgule.
a) Message simple :
cp /var/lib/ircd-hybrid/data /var/backups/ || echo "Erreur de copie"
b) Message + exit :
cp /var/lib/ircd-hybrid/data /var/backups/ || { echo "Erreur de copie"; exit 1; }
Notez les accolades avec espace, le point-virgule apres chaque commande
dans le groupe, et le ; final avant }.
Question 7 / 9 2> et /dev/null
backup-ircd.sh. Selon le contexte,
vous voulez envoyer les erreurs a 3 endroits differents.
/var/log/ircd-erreurs.log en ajout :2> = redirige stderr (ecrase). 2>> = stderr en append.
2>&1 = "envoyer 2 (stderr) au meme endroit que 1 (stdout)".
/dev/null = poubelle.
# a) stderr en append dans un fichier de log backup-ircd.sh 2>> /var/log/ircd-erreurs.log # b) stderr jete au neant (cron silencieux) backup-ircd.sh 2> /dev/null # c) stdout + stderr fusionnes backup-ircd.sh >> /var/log/ircd.log 2>&1 # Variante moderne : backup-ircd.sh &>> /var/log/ircd.log
Question 8 / 9 tester un resultat
ircd-hybrid est actif et,
sinon, le redemarrer. Donnez 2 versions du test.
a) Variante avec $? :
b) Variante avec if ! :
0 = reussi, autre = echec. $?
contient le code de la commande precedente. --quiet evite
l'affichage de "active"/"inactive".
# a) Avec $? (verbeux mais explicite)
systemctl is-active --quiet ircd-hybrid
if [ $? -ne 0 ]; then
systemctl restart ircd-hybrid
fi
# b) Avec if ! (plus elegant)
if ! systemctl is-active --quiet ircd-hybrid; then
systemctl restart ircd-hybrid
fi
Question 9 / 9 chainage logique
cmd1 && cmd2 : cmd2 si cmd1 reussit (ET logique court-circuit)cmd1 || cmd2 : cmd2 si cmd1 echoue (OU logique court-circuit)cmd1 ; cmd2 : cmd2 toujours (succes de cmd1 ignore)Pattern frequent :
mkdir -p /tmp/work && cd /tmp/work || exit 1 # creer + y aller ; sinon arret
Supplement
Non evalues a l'examen mais a connaitre dans un script pro
2 questions bonus
Supplement 1 set -e (non evalue)
|| partout.
a) Ligne en haut du script :
b) Option pour couvrir aussi les pipelines (cmd1 | cmd2 | cmd3) :
man bash section set. Pour les pipelines,
l'option commence par -o pipe...
#!/bin/bash set -e # arret au premier echec set -o pipefail # arret meme dans les pipelines set -u # arret si variable non definie # ou en une ligne : set -euo pipefail
Pourquoi pipefail : par defaut, le code de sortie d'un
pipeline est celui de la derniere commande. pipefail
renvoie l'erreur de la premiere qui echoue dans le pipeline.
Supplement 2 trap (non evalue)
/tmp/backup-en-cours.lock.
Vous voulez qu'il soit toujours efface a la fin,
meme si le script plante au milieu.
Ligne trap qui execute rm -f /tmp/backup-en-cours.lock a la sortie du script :
man bash section trap. Format :
trap 'commande' SIGNAL. Le signal EXIT
se declenche a la fin du script peu importe la cause.
trap 'rm -f /tmp/backup-en-cours.lock' EXIT
Cles :
EXIT = fin normale, exit, set -e, Ctrl+C...trap 'cleanup' EXIT INT TERMBilan
$?Supplements (non evalues) : set -euo pipefail et trap 'cleanup' EXIT
R pour recommencer.