web-dev-qa-db-fra.com

Pourquoi mon crontab ne fonctionne pas et comment puis-je le dépanner?

Il s'agit d'une Question canonique sur l'utilisation de cron & crontab.

Vous avez été dirigé ici parce que la communauté est assez sûre que la réponse à votre question se trouve ci-dessous. Si votre question ne reçoit pas de réponse ci-dessous, les réponses vous aideront à recueillir des informations qui aideront la communauté à vous aider. Ces informations doivent être modifiées dans votre question d'origine.

La réponse pour ' Pourquoi mon crontab ne fonctionne pas, et comment puis-je le dépanner? ' peut être vu ci-dessous. Cela concerne le système cron avec la crontab en surbrillance.

246
Eric Leschinski

Comment résoudre tous vos problèmes/problèmes liés à crontab (Linux)


Ceci est un wiki communautaire , si vous remarquez quelque chose de incorrect avec cette réponse ou si vous avez des informations supplémentaires, veuillez l'éditer.


Tout d'abord, la terminologie de base:

  • cron (8) est le démon qui exécute les commandes planifiées.
  • crontab (1) est le programme utilisé pour modifier les fichiers utilisateur crontab (5).
  • crontab (5) est un fichier par utilisateur qui contient des instructions pour cron (8).

Ensuite, l'éducation sur cron:

Chaque utilisateur d'un système peut avoir son propre fichier crontab. L'emplacement des fichiers crontab racine et utilisateur dépend du système mais ils sont généralement inférieurs à /var/spool/cron.

Il existe un fichier /etc/crontab À l'échelle du système, le répertoire /etc/cron.d Peut contenir des fragments crontab qui sont également lus et exécutés par cron. Certaines distributions Linux (par exemple, Red Hat) ont également /etc/cron.{hourly,daily,weekly,monthly} Qui sont des répertoires, des scripts à l'intérieur desquels seront exécutés toutes les heures/jour/semaine/mois, avec le privilège root.

root peut toujours utiliser la commande crontab; les utilisateurs réguliers peuvent ou non se voir accorder l'accès. Lorsque vous modifiez le fichier crontab avec la commande crontab -e Et l'enregistrez, crond vérifie sa validité de base mais ne garantit pas que votre fichier crontab est correctement formé. Il existe un fichier appelé cron.deny Qui spécifiera quels utilisateurs ne peuvent pas utiliser cron. L'emplacement du fichier cron.deny Dépend du système et peut être supprimé, ce qui permettra à tous les utilisateurs d'utiliser cron.

Si l'ordinateur n'est pas sous tension ou que le démon crond n'est pas en cours d'exécution et que la date/l'heure d'exécution d'une commande est passée, crond ne se rattrapera pas et exécutera les requêtes précédentes.

détails crontab, comment formuler une commande:

Une commande crontab est représentée par une seule ligne. Vous ne pouvez pas utiliser \ Pour étendre une commande sur plusieurs lignes. Le signe de hachage (#) Représente un commentaire qui signifie que tout ce qui se trouve sur cette ligne est ignoré par cron. Les espaces blancs et les lignes vides sont ignorés.

Soyez TRÈS prudent lorsque vous utilisez le signe pourcentage (%) Dans votre commande. À moins qu'ils ne soient échappés \%, Ils sont convertis en sauts de ligne et tout après le premier % Non échappé est passé à votre commande sur stdin.

Il existe deux formats pour les fichiers crontab:

  • Crontabs utilisateur

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  *   command to be executed
    
  • Fragments à l'échelle du système /etc/crontab Et /etc/cron.d

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    

Notez que ce dernier nécessite un nom d'utilisateur. La commande sera exécutée en tant qu'utilisateur nommé.

Les 5 premiers champs de la ligne représentent le ou les moments où la commande doit être exécutée. Vous pouvez utiliser des nombres ou, le cas échéant, des noms de jour/mois dans la spécification d'heure.

  • Les champs sont séparés par des espaces ou des tabulations.
  • Une virgule (,) Est utilisée pour spécifier une liste, par exemple 1,4,6,8, ce qui signifie exécuter à 1,4,6,8.
  • Les plages sont spécifiées par un tiret (-) Et peuvent être combinées avec des listes, par exemple 1-3,9-12 ce qui signifie entre 1 et 3 puis entre 9 et 12.
  • Le caractère / Peut être utilisé pour introduire une étape, par exemple 2/5 ce qui signifie commencer à 2 puis tous les 5 (2,7,12,17,22 ...). Ils ne terminent pas la fin.
  • Un astérisque (*) Dans un champ signifie toute la plage de ce champ (par exemple 0-59 Pour le champ des minutes).
  • Les plages et les étapes peuvent être combinées, par exemple */2 Signifie commencer au minimum pour le champ concerné puis tous les 2 par exemple 0 pour les minutes (0,2 ... 58), 1 pour les mois (1,3 ... 11) etc.

Débogage des commandes cron

Vérifiez le mail!

Par défaut, cron enverra toute sortie de la commande à l'utilisateur sous lequel il exécute la commande. S'il n'y a pas de sortie, il n'y aura pas de courrier. Si vous voulez que cron envoie du courrier à un autre compte, vous pouvez définir la variable d'environnement MAILTO dans le fichier crontab, par ex.

[email protected]
1 2 * * * /path/to/your/command

Capturez vous-même la sortie

Vous pouvez rediriger stdout et stderr vers un fichier. La syntaxe exacte pour capturer la sortie peut varier en fonction de ce que Shell cron utilise. Voici deux exemples qui enregistrent toutes les sorties dans un fichier à /tmp/mycommand.log:

1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1

Regardez les journaux

Cron enregistre ses actions via syslog, qui (selon votre configuration) va souvent à /var/log/cron Ou /var/log/syslog.

Si nécessaire, vous pouvez filtrer les instructions cron avec par exemple.

grep CRON /var/log/syslog 

Maintenant que nous avons passé en revue les bases de cron, où se trouvent les fichiers et comment les utiliser, examinons quelques problèmes courants.

Vérifiez que cron est en cours d'exécution

Si cron n'est pas en cours d'exécution, vos commandes ne seront pas planifiées ...

ps -ef | grep cron | grep -v grep

devrait vous procurer quelque chose comme

root    1224   1  0 Nov16 ?    00:00:03 cron

ou

root    2018   1  0 Nov14 ?    00:00:06 crond

Sinon, redémarrez-le

/sbin/service cron start

ou

/sbin/service crond start

Il peut y avoir d'autres méthodes; utilisez ce que fournit votre distribution.

cron exécute votre commande dans un environnement restreint.

Les variables d'environnement disponibles sont susceptibles d'être très limitées. En règle générale, seules quelques variables sont définies, telles que $LOGNAME, $HOME Et $PATH.

Il convient de noter en particulier que le PATH est limité à /bin:/usr/bin. La grande majorité des problèmes "mon script cron ne fonctionne pas" sont causés par ce chemin restrictif . Si votre commande se trouve dans un emplacement différent, vous pouvez résoudre ce problème de deux manières:

  1. Fournissez le chemin d'accès complet à votre commande.

    1 2 * * * /path/to/your/command
    
  2. Fournissez un CHEMIN approprié dans le fichier crontab

    PATH=/bin:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

Si votre commande nécessite d'autres variables d'environnement, vous pouvez également les définir dans le fichier crontab.

cron exécute votre commande avec cwd == $ HOME

Peu importe où le programme que vous exécutez réside sur le système de fichiers, le répertoire de travail actuel du programme lors de l'exécution de cron sera le répertoire personnel de l'utilisateur . Si vous accédez à des fichiers dans votre programme, vous devrez en tenir compte si vous utilisez des chemins d'accès relatifs, ou (de préférence) utilisez simplement des chemins d'accès qualifiés partout, et épargnez à tout le monde beaucoup de confusion.

La dernière commande de mon crontab ne s'exécute pas

Cron nécessite généralement que les commandes se terminent par une nouvelle ligne. Modifiez votre crontab; allez à la fin de la ligne qui contient la dernière commande et insérez une nouvelle ligne (appuyez sur Entrée).

Vérifiez le format crontab

Vous ne pouvez pas utiliser un utilisateur crontab formaté crontab pour/etc/crontab ou les fragments dans /etc/cron.d et vice versa. Un crontab formaté par l'utilisateur n'inclut pas de nom d'utilisateur à la 6ème position d'une ligne, tandis qu'un crontab formaté par le système inclut le nom d'utilisateur et exécute la commande en tant que cet utilisateur.

J'ai mis un fichier dans /etc/cron.{hourly,daily,weekly,monthly} et il ne fonctionne pas

  • Vérifiez que le nom de fichier n'a pas d'extension voir run-parts
  • Assurez-vous que le fichier dispose des autorisations d'exécution.
  • Dites au système ce qu'il faut utiliser lors de l'exécution de votre script (par exemple, mettez #!/bin/sh En haut)

Bogues liés à la date cron

Si votre date a été récemment modifiée par une mise à jour utilisateur ou système, un fuseau horaire ou autre, alors crontab commencera à se comporter de façon erratique et présentera des bogues bizarres, parfois en fonctionnement, parfois non. Il s'agit de la tentative de crontab d'essayer de "faire ce que vous voulez" lorsque le temps passe en dessous. Le champ "minute" deviendra inefficace après le changement d'heure. Dans ce scénario, seuls les astérisques seraient acceptés. Redémarrez cron et réessayez sans vous connecter à Internet (afin que la date n'ait pas la possibilité de se réinitialiser sur l'un des serveurs de temps).

Signes en pourcentage, encore une fois

Pour souligner les conseils sur les signes de pourcentage, voici un exemple de ce que cron en fait:

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

va créer le fichier ~/cron.out contenant les 3 lignes

foo
bar
baz

Ceci est particulièrement intrusif lors de l'utilisation de la commande date. Assurez-vous d'échapper aux signes de pourcentage

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"
352
Eric Leschinski

Debian Linux et ses dérivés (Ubuntu, Mint, etc.) ont certaines particularités qui peuvent empêcher l'exécution de vos tâches cron; en particulier, les fichiers dans /etc/cron.d, /etc/cron.{hourly,daily,weekly,monthly} doit :

  • appartenir à root
  • être accessible en écriture uniquement par root
  • ne pas être accessible en écriture par le groupe ou d'autres utilisateurs
  • avoir un nom sans aucun point '.' ou tout autre caractère spécial mais '-' et '_'.

Le dernier blesse régulièrement les utilisateurs sans méfiance; en particulier tout script dans l'un de ces dossiers nommé whatever.sh, mycron.py, testfile.pl, etc. sera pas exécuté, jamais.

D'après mon expérience, ce point particulier a été de loin la raison la plus fréquente d'un cronjob non exécuté sur Debian et ses dérivés.

Voir man cron pour plus de détails, si nécessaire.

25
wazoox

Si vos tâches cron cessent de fonctionner, vérifiez que votre mot de passe n'a pas expiré, car une fois qu'il l'a été, toutes les tâches cron s'arrêtent.
Il y aura des messages dans /var/log/messages similaire à celui ci-dessous qui montre des problèmes d'authentification de l'utilisateur:

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)

20
Munkeh72

Horaires rares et irréguliers

Cron est tout bien considéré comme un planificateur très basique et la syntaxe ne permet pas facilement à un administrateur de formuler des planifications légèrement plus rares.

Considérez le travail suivant qui serait généralement expliqué à "exécuter command toutes les 5 minutes":

*/5 * * * * /path/to/your/command

contre:

*/7 * * * * /path/to/your/command

qui ne fonctionne pas toujours exécutez command toutes les 7 minutes .

N'oubliez pas que le / Le caractère peut être utilisé pour introduire une étape mais ces étapes ne se terminent pas au-delà de la fin d'une série, par ex. */7 qui correspond à toutes les 7 minutes des minutes 0-59 soit 0,7,14,21,28,35,42,49,56 mais entre une heure et la suivante il y aura seulement 4 minutes entre les lots , après 00:56 une nouvelle série commence à 01:00, 01:07 etc. (et les lots ne s'exécuteront pas sur 01:03, 01:10, 01:17 etc.).


Que faire à la place?

Créez plusieurs lots

Plutôt qu'un seul travail cron, créez plusieurs lots qui combinent le résultat dans le calendrier souhaité.

Par exemple, pour exécuter un lot toutes les 40 minutes (00:00, 00:40, 01:20, 02:00, etc.), créez deux lots, l'un qui s'exécute deux fois aux heures paires et le second qui ne fonctionne que les heures impaires:

# The following lines create a batch that runs every 40 minutes i.e.

# runs on   0:00, 0:40,        02:00, 02:40         04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command

# runs on               01:20,               03:20,       etc to 23:20
20 1/2 * * * /path/to/your/command

# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.

Exécutez vos lots moins fréquemment

Plutôt que d'exécuter votre lot toutes les 7 minutes, ce qui est difficile à décomposer en plusieurs lots, exécutez-le simplement toutes les 10 minutes.

Démarrez vos lots plus fréquemment (mais empêchez plusieurs lots de s'exécuter simultanément)

De nombreux horaires étranges évoluent car les temps d'exécution des lots augmentent/fluctuent, puis les lots sont planifiés avec un peu de marge de sécurité supplémentaire pour empêcher les exécutions suivantes du même lot de se chevaucher et de s'exécuter simultanément.

Au lieu de cela, pensez différemment et créez un cronjob qui échouera gracieusement lorsqu'une exécution précédente n'est pas encore terminée, mais qui s'exécutera autrement. Voir ceci Q&A :

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job 

Cela démarrera presque immédiatement une nouvelle exécution une fois l'exécution précédente de/usr/local/bin/frequent_cron_job terminée.

Commencez vos lots plus fréquemment (mais quittez gracieusement lorsque les conditions ne sont pas réunies)

Étant donné que la syntaxe cron est limitée, vous pouvez décider de placer des conditions et une logique plus complexes dans le travail par lots lui-même (ou dans un script d'encapsulation autour du travail par lots existant) . Cela vous permet d'utiliser les capacités avancées de vos langages de script préférés, de commenter votre code et d'éviter les constructions difficiles à lire dans l'entrée crontab elle-même.

En bash le seven-minute-job ressemblerait alors à quelque chose comme:

#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated

if [ ! -f /tmp/lastrun ] ; then
    touch /tmp/lastrun
fi

if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
     # The minimum interval of 7 minutes between successive batches hasn't passed yet.
    exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF

Que vous pouvez ensuite (essayer) exécuter en toute sécurité toutes les minutes:

* * * * * /path/to/your/seven-minute-job

Un problème différent, mais similaire, consisterait à planifier un lot pour qu'il s'exécute le premier lundi de chaque mois (ou le deuxième mercredi), etc.st ou 7e et le jour de la semaine n'est pas le lundi.

#!/bin/bash
# first-monday-of-the-month-Housekeeping-job

# exit if today is not a Monday (and prevent locale issues by using the day number) 
if [ $(date +%u) != 1 ] ; then
  exit 0
fi

# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
  exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#EOF

Que vous pouvez ensuite (tenter) d'exécuter en toute sécurité tous les lundis:

0 0 * * 1 /path/to/your/first-monday-of-the-month-Housekeeping-job

N'utilisez pas cron

Si vos besoins sont complexes, vous pourriez envisager d'utiliser un produit plus avancé conçu pour exécuter des plannings complexes (répartis sur plusieurs serveurs) et qui prend en charge les déclencheurs, les dépendances des tâches, la gestion des erreurs, les tentatives et la surveillance des tentatives, etc. Le jargon du secteur serait "entreprise" " planification des tâches et/ou" automatisation de la charge de travail ".

14
HBruijn

Spécifique à PHP

Si vous avez un travail cron comme:

php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log

Et en cas d'erreur, attendez-vous à ce qu'ils vous soient envoyés, mais ils ne le font pas - vérifiez cela.

PHP par défaut n'envoie pas d'erreurs à STDOUT. @see https://bugs.php.net/bug.php?id=22839

Pour résoudre ce problème, ajoutez dans le fichier php.ini de cli ou dans votre ligne (ou dans le wrapper bash de votre PHP):

  • --define display_startup_errors = 1
  • --define display_errors = 'stderr'

Le 1er réglage vous permettra d'avoir des fatals comme 'Memory oops' et le 2e - de les rediriger tous vers STDERR. Ce n'est qu'après avoir bien dormi que tout sera envoyé au courrier de votre racine au lieu d'être simplement connecté.

8
gaRex

Ajouter ma réponse d'ici pour être complet, et ajouter une autre ressource potentiellement utile:

L'utilisateur cron a un autre $PATH que vous:

Un problème fréquent que les utilisateurs font avec les entrées crontab est qu'ils oublient que cron s'exécute dans un environment différent de celui qu'ils utilisent en tant qu'utilisateur connecté. Par exemple, un utilisateur crée un programme ou un script dans son $HOME et saisissez la commande suivante pour l'exécuter:

$ ./certbot ... 

La commande s'exécute parfaitement depuis sa ligne de commande. L'utilisateur ajoute ensuite cette commande à son crontab, mais constate que cela ne fonctionne pas:

*/10 * * * * ./certbot ....

La raison de l'échec dans ce cas est que ./ est un emplacement différent pour l'utilisateur cron que pour l'utilisateur connecté. Autrement dit, le environment est différent! Le CHEMIN fait partie de environment, et il est généralement différent pour l'utilisateur cron. Pour compliquer ce problème, la environment pour cron n'est pas la même pour toutes les distributions * nix , et il existe plusieurs versions de cron

Une solution simple à ce problème particulier consiste à donner à l'utilisateur cron une spécification de chemin d'accès complète dans l'entrée crontab:

0 22 * * * /path/to/certbot .....

Qu'est-ce que cron l'utilisateur environment?

Dans certains cas, nous pouvons avoir besoin de connaître la spécification complète de environment pour cron sur notre système (ou nous pouvons simplement être curieux). Quel est le environment pour l'utilisateur cron, et en quoi est-il différent du nôtre? De plus, nous pouvons avoir besoin pour connaître le environment pour un autre utilisateur cron - root par exemple ... qu'est-ce que root l'utilisateur environment en utilisant cron? Une façon d'apprendre cela est de demander à cron de nous dire:

  1. Créez un script Shell dans votre répertoire personnel (~/) comme suit (ou avec l'éditeur de votre choix):
$ nano ~/envtst.sh
  1. Entrez ce qui suit dans l'éditeur, après avoir ajusté pour votre système/utilisateur:
#!/bin/sh 
/bin/echo "env report follows for user "$USER >> /home/you/envtst.sh.out 
/usr/bin/env >> /home/you/envtst.sh.out 
/bin/echo "env report for user "$USER" concluded" >> /home/you/envtst.sh.out
/bin/echo " " >> /home/you/envtst.sh.out
  1. Enregistrez le fichier, quittez l'éditeur et définissez les autorisations de fichier comme exécutable.
$ chmod a+rx ~/envtst.sh
  1. Exécutez le script que vous venez de créer et consultez la sortie dans /home/you/envtst.sh.out. Cette sortie affichera votre environnement actuel comme $USER vous êtes connecté en tant que:
$ ./envtst.sh $$ cat /home/you/envtst.sh.out
  1. Ouvrez votre crontab pour le modifier:
$ crontab -e -u root
  1. Entrez la ligne suivante au bas de votre crontab:
* * * * *  /home/you/envtst.sh >> /home/you/envtst.sh.err 2>&1

RÉPONSE: Le fichier de sortie /home/you/envtst.sh.out contiendra une liste des environment pour "l'utilisateur cron root". Une fois que vous savez cela, ajustez votre entrée crontab en conséquence.

Je ne peux pas spécifier le programme dont j'ai besoin dans mon crontab entrée:

L'entrée de programme pour crontab est bien sûr définie dans man crontab, et vous devriez lire ceci. Cependant, la lecture de man crontab, et comprendre le calendrier sont deux choses différentes. Et les essais et erreurs sur une spécification d'horaire peuvent devenir très fastidieux. Heureusement, il existe une ressource qui peut aider: le gourou crontab. . Entrez vos spécifications d'horaire, et il vous expliquera l'horaire dans un langage anglais simple.

Enfin, et au risque d'être redondant avec l'une des autres réponses ici, ne vous laissez pas piéger en pensant que vous êtes limité à une seule entrée crontab car vous avez un travail à planifier. Vous êtes libre d'utiliser autant d'entrées crontab que nécessaire pour obtenir le planning dont vous avez besoin.

0
Seamus