Planification de tâches sous Linux
Qu'est-ce que cron?
cron est un démon (service en arrière-plan) sous Linux qui exécute des tâches planifiées à des intervalles réguliers. Le nom vient du grec "chronos" (temps).
Composants du système cron
- Le démon crond : Service système qui s'exécute en permanence
- La crontab : Fichier de configuration contenant les tâches planifiées
- Les logs : Enregistrent l'exécution des tâches
Il existe quelques alternatives à cron, comme systemd timers ou at, mais cron reste le plus utilisé pour les tâches récurrentes, pour sa simplicité et sa compatibilité avec la plupart des distributions Linux.
La syntaxe crontab
crontab est l'outil pour éditer les fichiers de tâches planifiées. Chaque ligne dans une crontab représente une tâche avec une syntaxe spécifique.
On peut éditer la crontab avec la commande:
crontab -e
Cela ouvre l'éditeur de texte par défaut (souvent nano ou vi) et nous permet d'ajouter, modifier ou supprimer des tâches.
Format de base
Pour chaque tâche à planifier, il faut spécifier 5 champs de temps suivis de la commande à exécuter. Les champs de temps ont une structure fixe:
┌──────── Minute (0-59)
│ ┌────── Heure (0-23)
│ │ ┌──── Jour du mois (1-31)
│ │ │ ┌── Mois (1-12)
│ │ │ │ ┌─ Jour de la semaine (0-7, 0 et 7 = dimanche)
│ │ │ │ │
│ │ │ │ │
* * * * * commande à exécuter
Pour chaque emplacement (minute, heure, jour, mois, jour de la semaine), vous pouvez utiliser soit un chiffre (ex: 5 pour la 5ème minute), un caractère spécial, comme illustré dans le tableau ci-dessous.
Opérateurs spéciaux
| Opérateur | Signification | Exemple | Résultat |
|---|---|---|---|
* |
Tous | * * * * * |
Chaque minute |
, |
Liste | 0,30 * * * * |
À 0 et 30 minutes de chaque heure |
- |
Plage | 0 9-17 * * * |
Toutes les heures de 9h à 17h |
/ |
Intervalle | */15 * * * * |
Toutes les 15 minutes |
Quelques exmples:
| Expression | Signification |
|---|---|
0 0 * * * |
Tous les jours à minuit |
0 12 * * 1-5 |
Tous les jours de semaine à midi |
*/10 * * * * |
Toutes les 10 minutes |
0 0 1 * * |
Le 1er de chaque mois à minuit |
30 2 * * * |
Tous les jours à 2h30 du matin |
Syntaxes spéciales
Il est également possible de remplacer les 5 champs par des mots-clés spéciaux:
| Syntaxe | Équivalent | Utilisation |
|---|---|---|
@reboot |
- | Au démarrage du système |
@yearly |
0 0 1 1 * |
Une fois par an (1er janvier à minuit) |
@monthly |
0 0 1 * * |
Une fois par mois (le 1er à minuit) |
@weekly |
0 0 * * 0 |
Une fois par semaine (dimanche à minuit) |
@daily |
0 0 * * * |
Une fois par jour (à minuit) |
@hourly |
0 * * * * |
Chaque heure (à la minute 0) |
Ainsi, la ligne suivante exécute /home/user/backup.sh chaque jour à minuit:
@daily /home/user/backup.sh
et est équivalente à:
0 0 * * * /home/user/backup.sh
Types de crontab
Il existe deux principaux types de crontab sous Linux: le crontab utilisateur et la crontab système. Le crontab utilisateur est spécifique à chaque utilisateur, tandis que la crontab système est globale. La principale différence est que lorsqu'une tâche est définie dans la crontab utilisateur, elle s'exécute avec les permissions de cet utilisateur, et quand elle est définie dans la crontab système, elle peut s'exécuter avec les permissions de n'importe quel utilisateur spécifié.
Crontab utilisateur
Comme mentionné précédemment, la commande pour éditer la crontab utilisateur est:
crontab -e
Cette commande a pour effet de modifier le fichier de crontab de l'utilisateur qui est situé dans /var/spool/cron/crontabs/nom_utilisateur. Les tâches définies ici s'exécutent avec les permissions de cet utilisateur, et il n'est pas nécessaire d'utiliser sudo pour les éditer.
Commandes courantes :
crontab -e: Éditer la crontabcrontab -l: Lister les tâchescrontab -r: Supprimer toutes les tâchescrontab -u utilisateur -l: Voir la crontab d'un autre utilisateur (sudo requis)
Crontab système
Le crontab système ne se modifie pas par la commande crontab -e. Pour ajouter une tâche système, on édite le fichier /etc/crontab, on ajoute des fichiers dans /etc/cron.d/ ou on place des scripts dans les répertoires /etc/cron.hourly/, /etc/cron.daily/, etc.
Éditer /etc/crontab
Pour ajouter une tâche dans /etc/crontab, on utilise un éditeur de texte avec les droits administrateur, par exemple:
sudo nano /etc/crontab
La syntaxe dans ce fichier est légèrement différente que le crontab utilisateur car elle inclut une colonne supplémentaire pour spécifier l'utilisateur sous lequel la commande doit s'exécuter. La syntaxe est donc:
┌──────── Minute (0-59)
│ ┌────── Heure (0-23)
│ │ ┌──── Jour du mois (1-31)
│ │ │ ┌── Mois (1-12)
│ │ │ │ ┌─ Jour de la semaine (0-7, 0 et 7 = dimanche)
│ │ │ │ │
│ │ │ │ │
* * * * * utilisateur commande à exécuter
Par exemple, pour exécuter un script de maintenance en tant que root tous les jours à 2h du matin, on ajouterait la ligne suivante:
# Exécuter en tant que root tous les jours à 2h
0 2 * * * root /usr/local/bin/maintenance.sh
Un autre exemple pour exécuter un script de nettoyage en tant que www-data toutes les heures:
# Exécuter en tant que www-data toutes les heures
0 * * * * www-data /var/www/scripts/cleanup.sh
Par défaut, le fichier /etc/crontab contient les trois lignes suivantes qui exécutent les scripts dans les répertoires /etc/cron.hourly/, /etc/cron.daily/, etc.:
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6 * * 7 root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6 1 * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
Ces lignes permettent d'exécuter automatiquement les scripts placés dans ces répertoires à des intervalles réguliers, comme expliqué plus loin.
Utiliser /etc/cron.d/
L'autre méthode pour ajouter des tâches système est de créer des fichiers dans le répertoire /etc/cron.d/. Chaque fichier doit suivre la même syntaxe que /etc/crontab, incluant le champ utilisateur.
Par exemple, on pourrait créer un fichier /etc/cron.d/backup avec le contenu suivant:
# Sauvegarde quotidienne en tant que root
0 3 * * * root /usr/local/bin/backup.sh
La différence entre cette méthode et la précédente est principalement organisationnelle. Utiliser /etc/cron.d/ permet de mieux organiser les tâches par service ou application, tandis que /etc/crontab est un fichier unique pour toutes les tâches système.
Utiliser les répertoires cron.
Finalement, nous avons les répertoires /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, et /etc/cron.monthly/. Ces répertoires sont utilisés pour exécuter des scripts à des intervalles réguliers sans avoir à modifier la crontab directement.
| Répertoire | Fréquence d'exécution |
|---|---|
/etc/cron.hourly/ |
Chaque heure |
/etc/cron.daily/ |
Chaque jour |
/etc/cron.weekly/ |
Chaque semaine |
/etc/cron.monthly/ |
Chaque mois |
Lorsque vous placez un script dans l'un de ces répertoires, il sera exécuté automatiquement à la fréquence correspondante. Assurez-vous que le script est exécutable (chmod +x script.sh). Le script sera exécuté avec les permissions de l'utilisateur root.
Cette méthode est particulièrement utile pour que les applications ou services puissent ajouter leurs propres tâches planifiées sans modifier les fichiers de crontab.
Environnement d'exécution de cron
Le problème
Lorsqu'un script s'exécute via cron, il s'exécute dans un environnement très différent que s'il était lancé manuellement dans un terminal. Cela peut entraîner des erreurs subtiles, car certaines commandes ou variables d'environnement attendues peuvent ne pas être disponibles. Le tableau suivant illustre les différences principales entre un shell interactif et l'environnement cron.
| Aspect | Shell interactif | Environnement cron |
|---|---|---|
| PATH | /home/user/bin:/usr/local/bin:/usr/bin:/bin |
/usr/bin:/bin |
| Profils chargés | .bashrc, .profile |
Aucun |
| Variables | Nombreuses (DISPLAY, etc.) | Minimales (HOME, USER, SHELL) |
| Shell par défaut | Votre shell configuré | /bin/sh |
Ainsi, un script qui fonctionne manuellement peut échouer avec cron parce que :
- Les commandes ne sont pas trouvées (PATH limité)
- Les variables d'environnement attendues n'existent pas car le profil n'est pas chargé
- Les chemins relatifs ne pointent pas où vous pensez
Ainsi, lors de l'écriture de scripts pour cron, il est crucial de prendre en compte ces différences. Voici quelques solutions courantes.
Utiliser des chemins absolus
Pour éviter les problèmes de PATH, utilisez toujours des chemins absolus pour les commandes et fichiers dans vos scripts. Par exemple, au lieu de tar -czf ..., utilisez /usr/bin/tar -czf ....
#!/bin/bash
/usr/bin/tar -czf /home/user/backup.tar.gz /home/user/data
Définir l'environnement dans la crontab À l'intérieur même du fichier crontab, vous pouvez définir des variables d'environnement comme PATH ou SHELL en haut du fichier. Cela fera en sorte que toutes les tâches définies dans cette crontab héritent de ces variables.
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
MAILTO=admin@example.com
0 2 * * * /home/user/script.sh
Charger l'environnement dans le script
Si votre script dépend de variables ou de configurations spécifiques à votre utilisateur, vous pouvez explicitement charger votre profil au début du script. Par exemple, si vous utilisez bash et que vos configurations sont dans ~/.bashrc ou ~/.profile, ajoutez cette ligne au début de votre script:
#!/bin/bash
source ~/.profile
# Maintenant les commandes de votre PATH personnel sont disponibles
Redirection et journalisation
Lorsqu'un script est planifié et exécuté automatiquement, il est crucial d'obtenir des informations sur son exécution: quand le script a été lancé, s'il a réussi ou échoué, et toute sortie ou erreur générée. Ces informations viennent de deux endroits: les sorties de la commande elle-même (stdout et stderr, qui nous indiquerait si quelque chose s'est mal passé) et les logs du système (qui nous diraient si cron a rencontré des problèmes pour lancer la tâche, comme un chemin d'accès manquant).
Nous parlerons donc de la redirection des sorties dans les scripts cron et de la consultation des logs système.
Redirection des sorties dans les scripts cron
Par défaut, cron capture la sortie standard (stdout) et la sortie d'erreur (stderr) de chaque tâche et les envoie par email à l'utilisateur propriétaire de la crontab, à partir du moment où un serveur de messagerie est configuré sur le système. Il est cependant plus pratique de conserver les logs localement. Il faut donc rediriger explicitement ces sorties vers des fichiers de log.
Rappel sur les sorties et la redirection
Les notions sur les sorties et la redirection sous Linux devraient vous être familières, mais voici un bref rappel pour se rafraîchir la mémoire.
En général sous Linux, chaque commande peut produire deux types de sorties:
- stdout (1) : La sortie standard, utilisée pour les messages normaux
- stderr (2) : La sortie d'erreur, utilisée pour les messages d'erreur
Par défaut, lorsque nous exécutons une commande dans un terminal, ces deux sorties s'affichent à l'écran, et il n'y a pas de distinction entre elles. Il est possible de rediriger chacune de ces sorties vers des fichiers ou d'autres commandes.
Redirections de base
| Syntaxe | Description | Exemple |
|---|---|---|
> |
Rediriger stdout vers un fichier (écrase le fichier) | |
>> |
Rediriger stdout vers un fichier (ajoute à la fin) | |
2> |
Rediriger stderr vers un fichier (écrase le fichier) | |
2>> |
Rediriger stderr vers un fichier (ajoute à la fin) | |
&> |
Rediriger stdout et stderr vers un fichier (écrase le fichier) | |
&>> |
Rediriger stdout et stderr vers un fichier (ajoute à la fin) |
Exemples:
# Rediriger stdout vers un fichier
commande > sortie.txt
# Rediriger stderr vers un fichier
commande 2> erreurs.txt
# Rediriger stdout et stderr vers un fichier
commande &> tout.txt
# Rediriger stdout et stderr vers un fichier (ajout)
commande &>> tout.txt
La syntaxe 2>&1 est utilisée pour rediriger stderr vers le même endroit que stdout. Par exemple:
commande > sortie.txt 2>&1
Cela signifie que stdout est redirigé vers sortie.txt, et stderr est redirigé vers le même endroit que stdout, donc également dans sortie.txt.
Finalement, pour ignorer toute sortie, on peut rediriger vers /dev/null, qui est un "trou noir" pour les données:
commande > /dev/null 2>&1
Cela fait disparaître toute sortie, qu'elle soit normale ou d'erreur.
Redirections courantes pour les cron jobs
Maintenant, lorsqu'il est question d'enregistrer les sorties de vos scripts cron, vous pouvez spécifier la redirection directement dans la crontab. Voici quelques exemples courants:
Tout capturer dans un log :
0 2 * * * /script.sh >> /var/log/script.log 2>&1
>>: Append (ajouter) à stdout2>&1: Rediriger stderr (2) vers stdout (1)
Séparer succès et erreurs :
0 2 * * * /script.sh >> /var/log/success.log 2>> /var/log/errors.log
Ignorer toute sortie :
0 2 * * * /script.sh > /dev/null 2>&1
Ne garder que les erreurs :
0 2 * * * /script.sh > /dev/null 2>> /var/log/errors.log
Logs système de cron
Maintenant que nous avons vu comment capturer les sorties de nos scripts, il est aussi important de savoir où trouver les logs système de cron lui-même. Cron enregistre ses propres activités dans les logs système :
Ubuntu/Debian avec rsyslog : /var/log/syslog
grep CRON /var/log/syslog
CentOS/RHEL avec rsyslog : /var/log/cron
grep CRON /var/log/cron
Distributions utilisant journald :
sudo journalctl -u cron
Ce qui est enregistré :
- Début d'exécution d'une tâche
- Fin d'exécution
- Utilisateur qui a exécuté la tâche
- Commande exécutée
Ce qui N'est PAS enregistré :
- La sortie de votre script (stdout/stderr)
- Le code de retour détaillé
Dépannage
Lorsqu'une tâche cron ne s'exécute pas comme prévu, cela peut être difficile de trouver la source du problème. Il y a plusieurs étapes de dépannage à suivre pour identifier et résoudre le problème.
Checklist de vérification
Le service cron est-il actif ?
sudo systemctl status cronLe script est-il exécutable ?
ls -l /chemin/vers/script.sh # Devrait montrer -rwxr-xr-xLe script fonctionne-t-il manuellement ?
/chemin/vers/script.sh echo $? # 0 = succèsLa syntaxe cron est-elle correcte ?
- Utilisez des outils en ligne pour valider : crontab.guru
Y a-t-il des erreurs dans les logs ?
grep CRON /var/log/syslog | grep $(whoami)