401 votes

Pourquoi mon crontab ne fonctionne-t-il pas et comment puis-je le résoudre ?

Il s'agit d'un Question canonique sur l'utilisation de cron et crontab.

Vous avez été dirigé ici parce que la communauté est assez sûre que la réponse à votre question peut être trouvée ci-dessous. Si votre question ne trouve pas de réponse ci-dessous, les réponses vous aideront à rassembler des informations qui permettront à la communauté de vous aider. Ces informations doivent être éditées dans votre question originale.

La réponse à la question Pourquoi mon crontab ne fonctionne-t-il pas et comment puis-je le résoudre ? peut être vu ci-dessous. Cela répond à la cron système avec la crontab en surbrillance.

4 votes

C'est une énorme copie de Raisons pour lesquelles la crontab ne fonctionne pas sur AskUbuntu.

1 votes

Il semble qu'Eric ait besoin d'avoir plus de réputation.

1 votes

Je viens de rejoindre Server Fault SE (donc seulement 101 rep), mais j'aimerais donner un -1 à cette question ! Cette question a-t-elle été posée uniquement pour obtenir des points de fidélité ? @IamtheMostStupidPerson Totalement d'accord avec vous...

6voto

Seamus Points 238

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

El cron l'utilisateur a une $PATH que vous :

Un problème fréquent que rencontrent les utilisateurs avec crontab est qu'ils oublient que cron fonctionne dans un autre environment qu'en tant qu'utilisateur connecté. Par exemple, un utilisateur crée un programme ou un script dans son ordinateur. $HOME et entrez 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 le cron qu'il ne l'est pour l'utilisateur connecté. C'est-à-dire que le environment est différent ! Le PATH fait partie de la environment et il est généralement différent pour le cron utilisateur. Ce qui complique cette question est que le environment for cron n'est pas le même pour tous *nix distributions, et il y a plusieurs versions de cron

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

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

Quel est le cron de l'utilisateur environment ?

Dans certains cas, nous pouvons avoir besoin de connaître le nom complet de l'entreprise. environment spécification pour cron sur notre système (ou nous sommes simplement curieux). Quel est le environment pour le cron utilisateur, et en quoi est-il différent du nôtre ? De plus, nous pouvons avoir besoin de connaître le environment pour un autre cron utilisateur - root par exemple... quel est le root de l'utilisateur environment en utilisant cron ? Une façon de le savoir est de demander cron pour nous le dire :

  1. Créez un Shell Shell dans votre répertoire personnel ( ~/ ) comme suit (ou avec le rédacteur de votre choix) :

    $ nano ~/envtst.sh

  2. Saisissez les données suivantes dans l'éditeur, après les avoir adaptées à 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

  3. Enregistrez le fichier, quittez l'éditeur et définissez les autorisations du fichier comme exécutable.

    $ chmod a+rx ~/envtst.sh

  4. Exécuter le script que vous venez de créer, et examiner la sortie dans /home/you/envtst.sh.out . Cette sortie montrera votre environnement actuel comme le $USER vous êtes connecté en tant que :

    $ ./envtst.sh $$ cat /home/you/envtst.sh.out

  5. Ouvrez votre crontab pour l'édition :

    $ crontab -e -u root

  6. Saisissez 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 "root cron". Une fois que vous savez cela, ajustez votre crontab en conséquence.

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

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

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 crontab car vous n'avez qu'une seule tâche à programmer. Vous êtes libre d'utiliser autant de crontab les entrées dont vous avez besoin pour obtenir le programme dont vous avez besoin.

2 votes

Pour moi, l'environnement différent a toujours causé des problèmes avec cron. Cette réponse devrait être davantage upvoted.

0 votes

@speedplane : On ne pourrait être plus d'accord :)

2voto

SurpriseDog Points 121

Comme l'a dit @Seamus, 99% de mes problèmes de crontab viennent du fait que j'ai des variables d'environnement différentes ou des PATH donc crontab ne peut pas trouver le script et il échoue silencieusement. Par conséquent, ma solution était d'écrire un script enveloppant qui :

  1. Définit le PATH variable au même que celui auquel je suis habitué.
  2. Définit mon PYTHONPATH à mon modèle personnalisé pour inclure toutes mes fonctions courantes.
  3. Change le DISPLAY ET DBUS variables pour que les applications graphiques comme les messages de notification et d'envoi soient effectivement affichés à l'écran.
  4. Change le répertoire de travail actuel pour le même que celui du script. (Si applicable)
  5. Lance le script avec nice ionice -c3 pour économiser les ressources.
  6. Enregistre le stdout y stderr du script dans le répertoire "logs" de sorte que lorsque quelque chose ne va pas, je puisse réellement trouver ce qui s'est passé.

Maintenant, si je veux lancer un script, il suffit d'éditer mycrontab avec crontab -e pour :

 mm hh * * * /path-to.../cron.launcher.py script.name.sh

et il exécute le script comme si j'essayais de le faire depuis le terminal sans aucune aggravation. A l'origine, il s'agissait d'un script BASH, mais il était bloqué par les arguments contenant des espaces, alors j'ai tout réécrit en Python. Il lancera même des applications GUI dans l'espace utilisateur :

#!/usr/bin/python3

# Runtime directories:
SYSPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
PYTHONPATH = ""

################################################################################
import os
import time
import sys
import subprocess

# Get username passed by crontab
user = os.environ['LOGNAME']
uid = subprocess.check_output(('id -u ' + user).split()).decode().strip()
gid = subprocess.check_output(('id -g ' + user).split()).decode().strip()

# Set Environmental Variables:
os.environ["PATH"] = SYSPATH
os.environ["PYTHONPATH"] = PYTHONPATH
os.environ["DISPLAY"] = ":0"
os.environ["XAUTHORITY"] = os.path.join('/home', user, '.Xauthority')
os.environ["DBUS_SESSION_BUS_ADDRESS"] = 'unix:path=' + os.path.join('/run/user', uid, 'bus')
os.environ["XDG_RUNTIME_DIR"] = os.path.join("/run/user", uid)

# Get args:
script = sys.argv[1]
args = sys.argv[2:]
name = os.path.basename(script)
basedir = os.path.dirname(sys.argv[0])

# Log dir
logdir = os.path.join(basedir, 'cron.logs')
log = os.path.join(logdir, name + '.' + str(int(time.time())) + '.log')
os.makedirs(logdir, exist_ok=True)
if not os.access(logdir, os.W_OK):
    print("Can't write to log directory", logdir, file=sys.stderr)
    sys.exit(1)

# If running as root, lock up any scripts so others can't edit them before root runs them.
if os.geteuid() == 0:
    cron_log = os.path.join(logdir, 'cron.launcher.root.log')
    for path in [script, sys.argv[0]] + list(filter(None, PYTHONPATH.split(':'))):
        print("Setting permisisons for", path)
        subprocess.run(('chown root -R ' + path).split(), stderr=subprocess.PIPE, check=False)
        subprocess.run(('chmod og-w -R ' + path).split(), stderr=subprocess.PIPE, check=False)
else:
    cron_log = os.path.join(logdir, 'cron.launcher.log')
cron_log = open(cron_log, 'a')
logger = lambda *args: cron_log.write(' '.join(map(str, args)) + '\n')

# Run the script
output = open(log, mode='w')
if os.path.exists(script):
    os.chdir(os.path.dirname(script))
cmd = ['nice', 'ionice', '-c3'] + [script] + args
logger(time.strftime('\n%m-%d %H:%M', time.localtime()).lstrip('0'), user, "running:")
logger(cmd)
logger("in directory", os.getcwd(), "with log in", log)
start = time.time()
ret = subprocess.run(cmd, stdout=output, stderr=output, check=False)

# Cleanup
fmt = lambda num: ("{0:.3g}").format(num) if abs(num) < 1000 else str(int(num))
logger("Returned", ret.returncode, "after", fmt(time.time() - start), 'seconds')
output.close()
cron_log.close()

Assurez-vous de vérifier votre $PATH y $PYTHONPATH au cas où vous auriez besoin de les modifier pour qu'elles soient différentes.

1 votes

C'était mon cas. Merci pour votre aide !

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X