Automatiser une petite routine : entrée, sortie, contrôle et arrêt
Une petite routine tient en quatre cases : une entrée, une transformation, une sortie, un contrôle. Vous y ajoutez les conditions qui l’obligent à s’arrêter : écrites avant la première ligne de code, elles décident si l’automatisation vous fait gagner du temps ou répète une erreur plus vite que vous. Voici la méthode, puis trois exemples courts, renommage horodaté, alerte disque, sauvegarde hebdomadaire, dont les commandes ont été exécutées et les sorties conservées.
Sommaire
- Qu’est-ce qu’une « petite » routine ?
- Quels critères d’arrêt écrire avant la première ligne ?
- Exemple 1 : comment renommer des fichiers avec un horodatage ?
- Exemple 2 : comment alerter quand un disque dépasse 80 % ?
- Exemple 3 : comment vérifier une sauvegarde hebdomadaire ?
- Comment planifier sans rien installer de plus ?
- Comment savoir si la routine a tourné ?
- Quelles routines faut-il refuser d’automatiser ?
- Ce qu’une routine planifiée ne rattrape pas
- Repères pour aller plus loin

Aucune installation nécessaire : les exemples n’utilisent que la bibliothèque standard de Python et les outils GNU déjà présents sur une installation Linux courante : python3, date, df, find, tar, awk, systemd. Aucun greffon tiers, aucun paquet supplémentaire, aucun service externe. C’est un choix, pas une limite technique : une routine dont vous ne pouvez pas expliquer le fonctionnement ligne par ligne n’est pas une petite routine, c’est une dépendance.
Qu’est-ce qu’une « petite » routine ?
Une routine est petite quand vous pouvez décrire son travail en cinq lignes et la relire en entier en moins de cinq minutes. Quatre cases suffisent :
| Case | Question à laquelle elle répond | Exemple |
|---|---|---|
| Entrée | Qu’est-ce qui déclenche le travail, et sur quoi ? | trois fichiers à renommer dans un dossier |
| Transformation | Quelle opération unique est appliquée ? | ajouter un préfixe horodaté au nom |
| Sortie | Qu’est-ce qui existe après, que vous pouvez montrer ? | les fichiers renommés, ou un rapport |
| Contrôle | Comment savez-vous que c’est bien passé ? | une comparaison avant/après et un code de retour |
Une cinquième ligne, souvent oubliée, décide de la sûreté : la condition d’arrêt. « Si le compte des éléments ne correspond pas à ce que j’attends, je m’arrête sans rien écrire. »
Trois refus définissent la frontière :
- Refus de la routine qui fait deux métiers. Un script qui renomme et archive et envoie un courriel est trois scripts déguisés en un. Séparez : chaque partie devient testable seule.
- Refus du « workflow magique ». Un enchaînement de vingt nœuds que personne ne sait relire ne se répare pas. Si vous ne savez pas dire ce qui se passe entre l’entrée et la sortie, ce n’est pas encore automatisable.
- Refus de ce que vous ne comprenez pas. Automatiser un processus que vous faites mal à la main ne fait pas disparaître l’erreur : cela la multiplie par le nombre d’exécutions.
Quels critères d’arrêt écrire avant la première ligne ?
Ce tableau se remplit avant le code. Chaque ligne est une promesse que la routine doit tenir toute seule, à trois heures du matin, sans vous.
| Critère d’arrêt | Seuil observable | Comportement attendu | Comment le vérifier |
|---|---|---|---|
| Cible hors du dossier prévu | un chemin absolu différent du dossier de travail | arrêt immédiat, aucune écriture | le chemin résolu est affiché avant l’action |
| Nombre d’éléments inattendu | compte différent du compte attendu | arrêt avant écriture | la routine affiche le compte et attend un accord |
| Élément déjà traité | nom déjà horodaté (AAAAMMJJ-HHMM-) |
ignoré, jamais re-préfixé | relance immédiate : « à renommer : 0 » |
| Nom de destination occupé | le fichier cible existe déjà | arrêt : l’écrasement est silencieux sur Unix | la garde de collision rend rc=1 avant tout appel à rename |
| Espace disque insuffisant | seuil de pourcentage franchi | arrêt du travail d’écriture, alerte | la mesure est faite avant, pas après |
| Étape précédente en échec | code de retour non nul | arrêt, pas de poursuite « quand même » | la chaîne est coupée par && ou par un test |
| Entrée non reconnue | format, extension ou encodage inattendu | mise en attente, aucune suppression | le fichier reste sur place et est listé |
| Durée anormale | dépassement d’un délai que vous fixez | arrêt et alerte | un horodatage de début et de fin est écrit |
| Archive illisible | lecture du contenu en échec | alerte ; aucune purge de l’ancien jeu | tar -tzf est exécuté après chaque écriture |
| Action irréversible | suppression, envoi externe, paiement | arrêt et revue humaine obligatoire | l’action est isolée dans sa propre commande |
Deux critères méritent d’être distingués des autres. « Nombre d’éléments inattendu » et « durée anormale » sont des détecteurs de dérive : ils n’empêchent pas l’erreur, ils empêchent l’erreur de se répéter mille fois. Une routine qui n’en a aucun finira par traiter un dossier qu’elle n’aurait jamais dû voir.
Un dernier critère n’appartient pas au code : si personne ne peut décrire en une phrase ce que la routine a le droit de faire, l’automatisation s’arrête là.
Exemple 1 : comment renommer des fichiers avec un horodatage ?
Cas d’usage banal : un dossier reçoit des pièces jointes au fil de l’eau, et vous voulez retrouver l’ordre d’arrivée. Ajouter un préfixe horodaté suffit.
Deux variables, fixées une fois pour toutes, le dossier de travail et son parent :
ATELIER="$HOME/atelier"
DOSSIER="$ATELIER/scans"
Le préfixe est fabriqué par strftime avec le format %Y%m%d-%H%M : année, mois, jour, heure et minute, chacun sur deux chiffres ou plus, sans séparateur de date (bibliothèque standard Python 3.12, datetime (nouvel onglet)). Comme chaque champ est de largeur fixe, un tri alphabétique classe ces noms dans l’ordre chronologique, ce qu’un explorateur de fichiers fait aussi.
Première commande : le repérage, en lecture seule. Elle n’écrit rien. La même commande sert de garde anti-doublon grâce à l’expression régulière ^\d{8}-\d{4}-, qui reconnaît un nom déjà horodaté.
python3 -c "import datetime,pathlib,re,sys; d=pathlib.Path(sys.argv[1]); s=datetime.datetime.now().strftime('%Y%m%d-%H%M'); deja=re.compile(r'^\d{8}-\d{4}-'); a=[p for p in sorted(d.glob('*.txt')) if not deja.match(p.name)]; print('prefixe :', s); print('a renommer :', len(a)); [print(' ', p.name, '->', s+'-'+p.name) for p in a]" "$DOSSIER"
État du dossier avant, puis sortie relevée :
ls -1 "$DOSSIER"
facture mars.txt
note.txt
piece.bin
rapport.txt
prefixe : 20260915-0353
a renommer : 3
facture mars.txt -> 20260915-0353-facture mars.txt
note.txt -> 20260915-0353-note.txt
rapport.txt -> 20260915-0353-rapport.txt
Trois éléments annoncés : c’est le compte attendu. Le fichier piece.bin n’apparaît pas, puisqu’il ne porte pas l’extension visée. Le préfixe est calculé à la minute ; si vous exécutez la commande suivante dans la minute qui vient, la cible sera exactement celle annoncée, sinon, refaites le repérage.
Deuxième commande : l’application. Le même filtre est repris, mot pour mot.
python3 -c "import datetime,pathlib,re,sys; d=pathlib.Path(sys.argv[1]); s=datetime.datetime.now().strftime('%Y%m%d-%H%M'); deja=re.compile(r'^\d{8}-\d{4}-'); a=[p for p in sorted(d.glob('*.txt')) if not deja.match(p.name)]; [p.rename(d/(s+'-'+p.name)) for p in a]" "$DOSSIER"
Troisième commande : le contrôle.
ls -1 "$DOSSIER"
20260915-0353-facture mars.txt
20260915-0353-note.txt
20260915-0353-rapport.txt
piece.bin
Trois fichiers renommés, un fichier intact : les deux comptes correspondent à l’annonce. Les espaces dans facture mars.txt n’ont pas été altérés : le nom est passé d’un objet Path à un autre, sans passer par une chaîne de caractères interprétée par le shell.
Quatrième commande : la relance. C’est le test le plus utile, et le plus souvent oublié.
python3 -c "import datetime,pathlib,re,sys; d=pathlib.Path(sys.argv[1]); s=datetime.datetime.now().strftime('%Y%m%d-%H%M'); deja=re.compile(r'^\d{8}-\d{4}-'); a=[p for p in sorted(d.glob('*.txt')) if not deja.match(p.name)]; print('prefixe :', s); print('a renommer :', len(a)); [print(' ', p.name, '->', s+'-'+p.name) for p in a]" "$DOSSIER"
prefixe : 20260915-0353
a renommer : 0
Zéro. Relancer la routine ne produit pas de doublon : c’est ce qui la rend compatible avec un planificateur qui pourrait la déclencher deux fois.
Cinquième commande : la garde de collision. Le filtre « déjà horodaté » protège contre le double préfixe, pas contre un nom de destination occupé pour une autre raison. Cette garde le vérifie et rend l’information par son code de retour. Elle accepte l’estampe en second argument, ce qui la rend testable sur un cas choisi. Un dossier de démonstration et un seul fichier :
mkdir -p "$ATELIER/demo-collision" && printf 'piece\n' > "$ATELIER/demo-collision/recu.txt"
python3 -c "import datetime,pathlib,re,sys; d=pathlib.Path(sys.argv[1]); s=sys.argv[2] if len(sys.argv) > 2 else datetime.datetime.now().strftime('%Y%m%d-%H%M'); deja=re.compile(r'^\d{8}-\d{4}-'); a=[p for p in sorted(d.glob('*.txt')) if not deja.match(p.name)]; occ=[p.name for p in a if (d/(s+'-'+p.name)).exists()]; print('estampe :', s); print('collisions :', len(occ)); [print(' ', n) for n in occ]; sys.exit(1 if occ else 0)" "$ATELIER/demo-collision" 20260915-0341; echo "rc=$?"
estampe : 20260915-0341
collisions : 0
rc=0
Le même appel, une fois la cible 20260915-0341-recu.txt créée entre-temps :
estampe : 20260915-0341
collisions : 1
recu.txt
rc=1
rc=1 est le signal d’arrêt : la routine ne doit pas appeler rename et doit signaler l’élément. C’est le type de vérification qui tient en une ligne et remplace une relecture manuelle.
Le piège que ce filtre évite
Sur Unix, Path.rename remplace silencieusement un fichier de destination qui existe déjà, sans avertissement, si vous avez les droits : « On Unix, if target exists and is a file, it will be replaced silently if the user has permission » (bibliothèque standard Python 3.12, pathlib (nouvel onglet)). Sur Windows, la même opération lève une erreur. Sur un serveur Linux, rien ne vous prévient.
Relevé sur la machine de recette, avec deux fichiers de test :
python3 -c "import pathlib,sys; d=pathlib.Path(sys.argv[1]); (d/'c-a.txt').write_text('A\n'); (d/'c-b.txt').write_text('B\n'); (d/'c-a.txt').rename(d/'c-b.txt'); print('c-b.txt contient :', (d/'c-b.txt').read_text().strip()); print('c-a.txt existe encore :', (d/'c-a.txt').exists())" "$ATELIER"
c-b.txt contient : A
c-a.txt existe encore : False
Le contenu B a disparu sans message. C’est exactement pourquoi la garde de collision n’est pas une élégance mais un critère d’arrêt : le filtre « déjà horodaté » empêche le double préfixe, et la garde empêche de viser un nom qu’un fichier occupe déjà pour une autre raison. Si votre dossier peut contenir des noms qui ressemblent à un horodatage sans en être, resserrez le motif avant d’automatiser.
Exemple 2 : comment alerter quand un disque dépasse 80 % ?
Un serveur qui remplit son disque ne prévient personne. Une alerte à 80 % laisse le temps d’agir ; à 100 %, le temps est déjà perdu.
Version shell, avec df en format POSIX (une ligne par système de fichiers) et awk pour le seuil :
df -P -x tmpfs -x devtmpfs -x squashfs | awk 'NR>1 {gsub(/%/,"",$5); if ($5+0 >= 80) print $6, $5"%"}'
Sortie relevée :
/ 88%
L’alerte s’est déclenchée : sur cette machine, la racine est à 88 %. Avec un seuil à 5 %, la même commande liste aussi /boot et /boot/efi, de quoi vérifier que la lecture des colonnes est correcte avant de faire confiance au silence.
Version Python, qui porte l’alerte sur le code de retour, plus pratique à brancher sur un planificateur :
python3 -c "import shutil,sys; seuil=float(sys.argv[1]); t=shutil.disk_usage('/'); pct=100*(1-t.free/t.total); print('/', round(pct,1), '%'); sys.exit(1 if pct>=seuil else 0)" 80; echo "rc=$?"
/ 87.4 %
rc=1
Deux remarques de lecture. D’abord, les deux commandes ne donnent pas le même nombre, 88 % contre 87,4 %, parce que df arrondit à l’entier quand shutil.disk_usage renvoie des octets (bibliothèque standard Python 3.12, shutil (nouvel onglet) : « total, used and free, which are the amount of total, used and free space, in bytes »). Choisissez une seule source pour votre seuil et gardez-la. Ensuite, n’utilisez pas le code de retour de df comme signal d’alerte : le manuel GNU précise qu’un df qui ne produit aucune sortie est un échec, ce qui inverserait le sens de votre test (manuel GNU coreutils, df (nouvel onglet)) : « Failure includes the case where no output is generated ».
Sur une machine à plusieurs montages, une seule mesure sur / ne suffit pas : elle ignore un volume de données séparé. Listez les points de montage qui vous concernent et mesurez-les un par un.
Exemple 3 : comment vérifier une sauvegarde hebdomadaire ?
Une sauvegarde non relue n’est pas une sauvegarde : c’est un fichier dont vous espérez quelque chose. La routine tient donc en trois temps, écrire, relire, comparer. Précision utile : l’exemple ci-dessous écrit une archive tar.gz sur le même disque que la source, sans versionning, sans copie hors-ligne et sans chiffrement. Ce que vous obtenez est un instantané local vérifié, pas une sauvegarde au sens où l’entendent les guides de protection des données (copie externe, règle 3-2-1, restauration testée séparément). Pour passer de l’un à l’autre, ajoutez vous-même ces étapes : copie externe, copie chiffrée, vérification sur une autre machine. Le dossier qui reçoit les archives est fixé lui aussi :
ARCHIVES="$ATELIER/archives"
Création de l’archive :
tar -czf "$ARCHIVES/sauvegarde-$(date +%Y%m%d).tar.gz" -C "$ATELIER" scans
ls -1 "$ARCHIVES"; stat -c '%n %s octets' "$ARCHIVES/sauvegarde-$(date +%Y%m%d).tar.gz"
sauvegarde-20260915.tar.gz
/tmp/csdf-routine-…/archives/sauvegarde-20260915.tar.gz 273 octets
L’archive existe. La relire est la seule façon de le savoir :
tar -tzf "$ARCHIVES/sauvegarde-$(date +%Y%m%d).tar.gz"
scans/
scans/20260915-0353-facture mars.txt
scans/20260915-0353-rapport.txt
scans/20260915-0353-note.txt
scans/piece.bin
Cinq lignes : le dossier et les quatre fichiers. La comparaison avec le disque est le contrôle qui manque le plus souvent :
tar -dzf "$ARCHIVES/sauvegarde-$(date +%Y%m%d).tar.gz" -C "$ATELIER"; echo "rc=$?"
rc=0
Un code de retour nul signifie que chaque membre de l’archive correspond au fichier du disque en taille, droits, propriétaire, date et contenu. Attention à ce que ce contrôle mesure réellement : le manuel GNU tar précise que « the spirit behind the --compare (--diff, -d) option is to check whether the archive represents the current state of files on disk, more than validating the integrity of the archive media » (GNU tar, § 4.2.6 (nouvel onglet)). Ce n’est donc pas un contrôle du support : pour cela, l’option --verify (-W) vérifie l’archive au moment où elle est écrite (GNU tar, § 9.8 (nouvel onglet)).
Deux cas négatifs, relevés sur la même machine, donnent le comportement à prévoir dans votre journal. Le premier simule une archive corrompue en transit, son contenu est remplacé par des octets qui ne sont pas du gzip :
printf 'pas une archive gzip\n' > "$ARCHIVES/sauvegarde-20260915.tar.gz"
tar -tzf "$ARCHIVES/sauvegarde-20260915.tar.gz"; echo "rc=$?"
gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
rc=2
tar -tzf "$ARCHIVES/sauvegarde-19990101.tar.gz"; echo "rc=$?"
tar (child): …/sauvegarde-19990101.tar.gz: Cannot open: No such file or directory
tar: Child returned status 2
tar: Error is not recoverable: exiting now
rc=2
2 signifie « erreur fatale », 1 « certains fichiers diffèrent », 0 « terminaison réussie » (GNU tar, codes de sortie (nouvel onglet)). La règle de sécurité qui en découle est la dernière ligne du tableau des critères d’arrêt : la purge des anciennes archives ne s’exécute jamais avant qu’une archive du jour ait été relue avec succès. Une rotation de sauvegardes écrite dans l’ordre inverse finit par supprimer la seule copie valide.
Comment planifier sans rien installer de plus ?
Le planificateur naturel sur une distribution Linux moderne est le couple systemd timer + service. Les fichiers ci-dessous sont des exemples complets ; ils sont présentés, pas installés, et leur mise en place appartient à la personne qui administre la machine.
~/.config/systemd/user/sauvegarde-hebdo.timer :
[Unit]
Description=Sauvegarde hebdomadaire verifiee (exemple)
[Timer]
OnCalendar=Mon 06:30
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
Trois directives portent la sûreté. OnCalendar= accepte les noms de jours en anglais, indépendamment de la langue du système (systemd.time (nouvel onglet)). Persistent=true enregistre l’heure du dernier déclenchement : si la machine était éteinte au moment prévu, le service est déclenché au redémarrage, ce qui rattrape une exécution manquée (systemd.timer (nouvel onglet)). RandomizedDelaySec= répartit les déclenchements pour éviter que plusieurs machines ne se réveillent à la même seconde.
Ne devinez pas l’expression calendaire, vérifiez-la :
systemd-analyze calendar "Mon 06:30"
Original form: Mon 06:30
Normalized form: Mon *-*-* 06:30:00
Next elapse: Mon 2026-09-21 06:30:00 UTC
From now: 6 days left
La même commande rejette une expression en français dans un système configuré en anglais, utile comme garde de saisie :
systemd-analyze calendar "chaque lundi matin"
Failed to parse calendar specification 'chaque lundi matin': Invalid argument
Le service déclenché contient le travail, jamais la logique de planification. Un exemple pour l’alerte disque, avec le code de retour qui porte le signal :
[Unit]
Description=Verifier l'espace disque et alerter au-dela du seuil (exemple)
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 -c "import shutil,sys; seuil=float(sys.argv[1]); t=shutil.disk_usage(sys.argv[2]); pct=100*(1-t.free/t.total); print(sys.argv[2], round(pct,1), '%'); sys.exit(1 if pct>=seuil else 0)" 80 /
Vérifiez la syntaxe des unités avant de les activer, la commande se lance depuis le dossier qui contient les deux fichiers :
systemd-analyze verify ./sauvegarde-hebdo.timer ./alerte-disque.service; echo "rc=$?"
rc=0
Cette vérification n’est pas décorative : une citation non équilibrée dans ExecStart= est signalée comme une erreur fatale. Relevé sur une unité volontairement cassée :
Unbalanced quoting, ignoring: "/usr/bin/python3 -c "unterminated"
casse.service: Unit configuration has fatal error, unit will not be started.
Le message d’erreur confirme au passage une contrainte propre à systemd : la ligne ExecStart= est découpée selon les règles de citation de systemd, pas selon celles de votre shell. Si vous préférez éviter ce découpage, mettez la même commande dans un fichier exécutable et appelez-le par son chemin absolu, ExecStart=/usr/local/bin/alerte-disque.sh 80 /. Les deux formes passent la vérification ; choisissez celle que vous savez relire.
Équivalent cron, si vous préférez ce planificateur, une ligne, mêmes précautions, et un chemin absolu pour tout :
30 6 * * 1 /usr/local/bin/sauvegarde-hebdo.sh
Le choix entre les deux n’a rien de technique : prenez celui que vous savez inspecter. Un cron dont vous ne trouvez pas le journal est un planificateur que vous ne déboguerez pas.
Comment savoir si la routine a tourné ?
Une routine qui n’écrit pas de trace est une routine que vous relancerez pour « voir ». Trois éléments suffisent, et aucun ne contient de secret :
- Le code de retour.
0réussi, non nul en échec. C’est ce que lit le planificateur. - Une ligne de journal horodatée par exécution : identifiant, nombre d’éléments reçus, nombre traités, nombre ignoré, motif d’arrêt éventuel. Sur un timer
systemd, la sortie standard part dans le journal du service ; surcron, redirigez-la vers un fichier. - La preuve d’exécution : le rapport produit, la liste des fichiers touchés, la sortie conservée. Une routine dont le résultat n’est pas consultable n’a pas de contrôle, seulement une intention.
Relisez ensuite la réalité, pas le souhait :
journalctl --user -u sauvegarde-hebdo.service --since "8 days ago"
Sur une unité système, la même commande s’écrit sans --user et demande les droits de lecture du journal. Vérifiez qu’elle répond bien sur votre machine avant de compter sur elle : sur la machine de recette, un compte sans appartenance au groupe systemd-journal n’obtient que l’avertissement « No journal files were opened due to insufficient permissions ». Lire le journal est une permission, pas une évidence.
Et rappelez-vous le corollaire du contrôle : un planificateur peut manquer un déclenchement si la machine est éteinte, si l’horloge est fausse au démarrage, ou si un déclenchement précédent tourne encore. Ce sont des cas connus et documentés, pas des garanties d’exécution.
Quelles routines faut-il refuser d’automatiser ?
Trois signaux doivent arrêter le projet avant la première ligne.
Le processus n’est pas compris. Si vous ne savez pas expliquer, pour la version manuelle, ce qui entre, ce qui sort et ce qui compte comme un succès, l’automatisation fige une procédure que personne ne maîtrise. Commencez par écrire la procédure à la main, une fois, sur un cas réel ; l’automatisation viendra ensuite, et sera plus courte.
L’outil impose sa logique. Une chaîne d’automatisation qui masque ses propres étapes vous rend dépendant d’un service que vous ne pouvez ni lire, ni sauvegarder, ni faire tourner ailleurs. Ce n’est pas un interdit moral, c’est un coût : le jour où la connexion tombe ou que l’offre change, vous perdez la procédure avec l’outil. Préférez un enchaînement que vous pouvez réécrire en dix lignes.
L’action est irréversible sans revue. Suppression, envoi vers l’extérieur, paiement, publication : ces opérations peuvent être déclenchées par une routine, jamais décidées par elle. Séparez la préparation (automatisable) de la décision (humaine), et gardez une commande unique et lisible pour l’acte irréversible.
Un dernier repère pratique : si votre description dépasse cinq lignes ou fait apparaître un deuxième objectif, coupez en deux routines. Une petite routine qui fonctionne vaut mieux qu’une grande qui fonctionne parfois.
Ce qu’une routine planifiée ne rattrape pas
- Les sorties citées viennent d’une seule machine : Linux 6.8.0-106-generic, Python 3.12.3, GNU coreutils 9.4, GNU tar 1.35, GNU Awk 5.2.1, systemd 255. Les messages d’erreur, les colonnes de
dfet les codes de retour peuvent varier selon la distribution et la version. - Les deux unités
systemdsont présentées, jamais installées ni activées : leur syntaxe a été vérifiée, leur exécution réelle ne l’a pas été. - Les exemples ont été exécutés sur une seule machine et une seule distribution. Les valeurs numériques et la chronologie y sont attachées.
- Les commandes du parcours sont volontairement compactes pour tenir en une ligne. Pour un usage durable, mettez-les dans un fichier versionné : vous pourrez le relire, le corriger et le comparer d’une version à l’autre.
- Rien ici ne garantit qu’une routine ne produira jamais d’erreur. Une routine contrôlée est une routine dont les erreurs sont visibles, bornées et réparables.
Repères pour aller plus loin
- Automatiser : les autres méthodes du même univers.
- Les commandes Linux de base pour vous repérer dans un terminal avant d’écrire une routine.
- Fichiers et répertoires pour les gestes de copie, déplacement et vérification.
- Services et journaux systemd pour lire ce qu’un timer a réellement exécuté.
Écrivez les quatre cases et les critères d’arrêt de votre prochaine routine avant son code : c’est la partie qui décide du résultat, et celle que personne ne relit jamais.