GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi ma crontab ne fonctionne-t-elle pas et comment puis-je la dépanner ?

Solution 1 :

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

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

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, formation 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 /etc/crontab à l'échelle du système fichier, le /etc/cron.d Le répertoire peut contenir des fragments de crontab qui sont également lus et traité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 chaque heure/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 éditez le fichier crontab avec la commande crontab -e et enregistrez-le, crond vérifie sa validité de base mais ne garantit pas que votre fichier crontab est correctement formé. Il existe un fichier nommé cron.deny qui précisera quels utilisateurs ne peuvent pas utiliser cron. Le cron.deny l'emplacement du fichier 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 si 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 rattrapera pas et n'exécutera pas les requêtes passées.

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 hachage (# ) représente un commentaire qui signifie que tout ce qui se trouve sur cette ligne est ignoré par cron. Les espaces et les lignes vides en début de ligne sont ignorés.

Soyez TRÈS prudent lorsque vous utilisez le pourcentage (% ) connectez-vous à votre commande. Sauf s'ils sont échappés \% ils sont convertis en nouvelles lignes 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
    
  • À l'échelle du système /etc/crontab et /etc/cron.d fragments

     # 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 l'heure ou les heures auxquelles 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 de l'heure.

  • Les champs sont séparés par des espaces ou des tabulations.
  • Une virgule (, ) est utilisé 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 avec un tiret (- ) et peuvent être combinés avec des listes, par ex. 1-3,9-12 qui signifie entre 1 et 3 puis entre 9 et 12.
  • Le / Le caractère peut être utilisé pour introduire une étape, par ex. 2/5 c'est à dire à partir de 2 puis tous les 5 (2,7,12,17,22...). Ils ne dépassent pas la fin.
  • Un astérisque (* ) dans un champ signifie la plage entière pour ce champ (par exemple 0-59 pour le champ des minutes).
  • Les plages et les étapes peuvent être combinées, par ex. */2 signifie commencer au minimum pour le champ concerné puis tous les 2 par ex. 0 pour les minutes (0,2...58), 1 pour les mois (1,3...11) etc.

Débogage des commandes cron

Vérifiez le courrier !

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 compte différent, vous pouvez définir la variable d'environnement MAILTO dans le fichier crontab, par exemple

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

Capturez la sortie vous-même

Vous pouvez rediriger stdout et stderr vers un fichier. La syntaxe exacte pour capturer la sortie peut varier en fonction du shell cron utilisé. 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

Consultez 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 ne s'exécute pas, vos commandes ne seront pas planifiées ...

ps -ef | grep cron | grep -v grep

devrait vous donner 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 votre distribution fournit.

cron exécute votre commande dans un environnement restreint.

Les variables d'environnement disponibles sont probablement très limitées. En règle générale, vous n'obtiendrez que quelques variables définies, telles que $LOGNAME , $HOME , et $PATH .

Il convient de noter en particulier 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 à un emplacement différent, vous pouvez résoudre ce problème de plusieurs manières :

  1. Indiquez le chemin complet de votre commande.

     1 2 * * * /path/to/your/command
    
  2. Fournissez un PATH 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

Quel que soit l'endroit où le programme que vous exécutez réside sur le système de fichiers, le répertoire de travail actuel du programme lorsque cron l'exécute 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 relatifs, ou (de préférence) utilisez simplement des chemins entièrement qualifiés partout, et évitez à tout le monde beaucoup de confusion.

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

Cron exige 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érifier le format crontab

Vous ne pouvez pas utiliser un crontab utilisateur formaté par crontab pour /etc/crontab ou les fragments dans /etc/cron.d et vice versa. Une crontab formatée par l'utilisateur n'inclut pas de nom d'utilisateur en 6ème position d'une ligne, tandis qu'une crontab formatée 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 s'exécute pas

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

Bogues liés à la date de Cron

Si votre date est récemment modifiée par un utilisateur ou une mise à jour du système, un fuseau horaire ou autre, alors crontab commencera à se comporter de manière erratique et présentera des bogues bizarres, parfois fonctionnels, parfois non. C'est la tentative de crontab d'essayer de "faire ce que vous voulez" lorsque l'heure change par en dessous. Le champ "minute" deviendra inopérant 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 de pourcentage, encore une fois

Pour mettre l'accent sur les conseils concernant les signes de pourcentage, voici un exemple de ce que cron en fait :

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

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

foo
bar
baz

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

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

Méfiez-vous du Sudo

lors de l'exécution en tant qu'utilisateur non root,

crontab -e

ouvrira la crontab de l'utilisateur, tandis que

sudo crontab -e

ouvrira la crontab de l'utilisateur root. Il n'est pas recommandé d'exécuter des commandes sudo dans une tâche cron, donc si vous essayez d'exécuter une commande sudo dans le cron d'un utilisateur, essayez de déplacer cette commande vers le cron root et supprimez sudo de la commande.

Solution 2 :

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

  • être la propriété de root
  • uniquement accessible en écriture par root
  • ne pas être accessible en écriture par le groupe ou d'autres utilisateurs
  • avoir un nom sans point '.' ou tout autre caractère spécial sauf '-' et '_' .

Le dernier blesse régulièrement les utilisateurs peu méfiants; en particulier tout script dans l'un de ces dossiers nommé whatever.sh , mycron.py , testfile.pl , etc. ne seront pas être 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.

Solution 3 :

Si vos tâches cron cessent de fonctionner, vérifiez que votre mot de passe n'a pas expiré, car une fois qu'il a expiré, toutes les tâches cron s'arrêtent.
Il y aura des messages en /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)

Solution 4 :

Horaires inhabituels et irréguliers

Cron est tout 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 inhabituelles.

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 fait pas toujours exécutez command toutes les 7 minutes .

Rappelez-vous que le / Le caractère peut être utilisé pour introduire une étape, mais ces étapes ne s'étendent pas au-delà de la fin d'une série, par ex. */7 qui correspond toutes les 7 minutes à partir des minutes 0-59 c'est-à-dire 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 fonctionneront pas sur 01:03 , 01:10 , 01:17 etc.).

Que faire à la place ?

Créer plusieurs lots

Plutôt qu'une seule tâche cron, créez plusieurs lots qui, combinés, donnent le calendrier souhaité.

Par exemple, pour exécuter un batch toutes les 40 minutes (00:00, 00:40, 01:20, 02:00 etc.) créez deux batchs, un qui s'exécute deux fois les heures paires et le second qui ne s'exécute 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 un calendrier difficile à décomposer en plusieurs lots, exécutez-le simplement toutes les 10 minutes à la place.

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

De nombreux horaires impairs évoluent parce que les durées d'exécution des lots augmentent/fluctuent, puis les lots sont planifiés avec un peu de marge de sécurité supplémentaire pour éviter que les exécutions ultérieures du même lot ne se chevauchent et ne s'exécutent simultanément.

Au lieu de cela, pensez différemment et créez une tâche cron qui échouera correctement lorsqu'une exécution précédente n'est pas encore terminée, mais qui s'exécutera autrement. Voir cette FAQ :

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

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

Démarrez 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 wrapper autour du travail par lots existant). Cela vous permet d'utiliser les fonctionnalité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) d'exécuter en toute sécurité toutes les minutes :

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

Un problème différent, mais similaire, serait de programmer un lot pour qu'il s'exécute le premier lundi de chaque mois (ou le deuxième mercredi), etc. Il suffit de programmer le lot pour qu'il s'exécute tous les lundis et quittez lorsque la date n'est ni entre le 1 ou le 7 et le jour de la semaine n'est pas 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 (essayer) 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 pouvez envisager d'utiliser un produit plus avancé conçu pour exécuter des planifications complexes (distribuées 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 nouvelles tentatives, etc. " planification des tâches et/ou " automatisation de la charge de travail ".

Solution 5 :

Spécifique à PHP

Si vous avez une tâche cron comme :

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

Et en cas d'erreurs, attendez-vous à ce qu'elles vous soient envoyées, mais ce n'est pas le cas -- cochez ceci.

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

Pour résoudre ce problème, ajoutez dans cli`s php.ini ou dans votre ligne (ou dans votre wrapper bash pour PHP) ceci :

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

Le 1er paramètre vous permettra d'avoir des fatals comme 'Memory oops' et le 2ème -- de les rediriger tous vers STDERR. Ce n'est qu'une fois que vous pourrez bien dormir que tout sera envoyé au courrier de votre racine au lieu d'être simplement connecté.


Linux
  1. Redis comme cache :comment ça marche et pourquoi l'utiliser

  2. Pourquoi ne puis-je pas diviser un fichier .ape ?

  3. Comment puis-je trier les ls par propriétaire et groupe ?

  4. pourquoi sftp rmdir ne fonctionne-t-il pas?

  5. Comment puis-je monter une partition à chaque redémarrage ?

Comment savoir si un package est installé ou non sous Linux et Unix

Linux - Pourquoi utilisons-nous Su - Et pas seulement Su ?

Pourquoi Scp est-il si lent et comment le rendre plus rapide ?

Ubuntu – Crontab ne fonctionne pas ?

Pourquoi est-ce Rm -rf et non Rmdir -rf ?

Comment et pourquoi utiliser Linux pour installer Telnet