Question Exécuter un travail cron manuellement et immédiatement


(J'ai déjà lu Comment puis-je tester un nouveau script cron?.)

J'ai un problème spécifique (le travail cron ne semble pas s'exécuter correctement), mais le problème est général: j'aimerais déboguer les scripts cronés. Je suis conscient que je peux configurer une ligne crontab * * * * * *, mais ce n'est pas une solution pleinement satisfaisante. J'aimerais pouvoir exécuter un travail cron à partir de la ligne de commande comme s'il était exécuté par cron (même utilisateur, mêmes variables d'environnement, etc.). Y a-t-il un moyen de faire cela? Il n'est pas pratique d'attendre 60 secondes pour tester les modifications de script.


94
2017-11-18 13:55


origine


(désolé, impossible d'ajouter un commentaire) 0 30 16 20 *? * Même si vous exécutez le travail de cette manière, l’idée est de fournir une sortie de script permettant de voir ce qui ne va pas, à moins que le travail ne soit écrit dans un journal, c’est inutile.


Réponses:


Voici ce que j'ai fait, et cela semble fonctionner dans cette situation. Au moins, cela me montre une erreur, alors que courir depuis la ligne de commande car l’utilisateur n’affiche pas l’erreur.


Étape 1: J'ai mis cette ligne temporairement dans la crontab de l'utilisateur:

* * * * *   /usr/bin/env > /home/username/tmp/cron-env

puis l'a sorti une fois que le fichier a été écrit.

Étape 2: Fait moi-même un petit script bash run-as-cron contenant:

#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"

Alors, en tant qu'utilisateur en question, j'ai pu

run-as-cron /the/problematic/script --with arguments --and parameters

Cette solution pourrait évidemment être étendue pour utiliser sudo ou autre pour plus de flexibilité.

J'espère que cela aide les autres.


73
2017-11-18 14:40



Cela ne fonctionne pas pour moi et je me demande si cela convient à quelqu'un qui a voté. 1) Pourquoi utilisez-vous bash? Ce n'est pas nécessaire ici et il se peut qu'il ne soit pas situé dans /usr/bin. 2) le cat …/cron-env affiche plusieurs lignes, ce qui ne fonctionne pas. Juste essayer d'exécuter /usr/bin/env -i $(cat cron-env) echo $PATH dans le terminal, il sort littéralement l'environnement au lieu de l'utiliser. 3) L’environnement actuel fuit dans l’environnement cron émulé. Essayer: export foo=leaked; run-as-cron echo $foo. - Marco
@Marco Fonctionne dans bash, c'est ce que j'utilise car c'est un environnement mieux défini que sh. J'utilise tout de pdksh, ksh (plusieurs versions), bash et dash, je suis donc très conscient des différences entre les implémentations de "pure" de sh, même si je reste très strictement dans le sous-ensemble commun des langues. :-) - Max Murphy
@Marco 2. cat génère plusieurs lignes, ce qui fonctionne, car la substitution de shell les réduit en une seule ligne, que vous pouvez vérifier avec echo $(cat cron-env ) | wc; votre exemple de commande, /usr/bin/env -i $(cat cron-env) echo $PATH, substituts $PATH depuis le shell appelant; au lieu de cela, il devrait invoquer un sous-shell à substituer dans le sous-environnement, par exemple. /usr/bin/env -i $(cat cron-env) /bin/sh -c 'echo $PATH'. 3. Vous avez commis la même erreur en substituant à nouveau dans le shell d'appel au lieu de dans le sous-environnement - John Freeman


Je présente une solution basée sur la réponse de Pistos, mais sans les défauts.

  • Ajoutez la ligne suivante à la crontab, par exemple en utilisant crontab -e

    * * * * *  /usr/bin/env > /home/username/cron-env
    
  • Créez un script shell qui exécute une commande dans le même environnement que les tâches cron exécutées:

    #!/bin/sh
    
    . "$1"
    exec /usr/bin/env -i "$SHELL" -c ". $1; $2"
    

Utilisation:

run-as-cron <cron-environment> <command>

par exemple.

run-as-cron /home/username/cron-env 'echo $PATH'

Notez que le second argument doit être cité s'il nécessite un argument. La première ligne du script charge un shell POSIX en tant qu'interpréteur. La deuxième ligne source le fichier d’environnement cron. Ceci est nécessaire pour charger le shell correct, qui est stocké dans la variable d'environnement SHELL. Ensuite, il charge un environnement vide (pour éviter toute fuite de variables d’environnement dans le nouveau shell), lance le même shell qui est utilisé pour les tâches cron et charge les variables d’environnement cron. Enfin, la commande est exécutée.


34
2017-09-24 18:46



cela m'a aidé à reproduire mon erreur de chargement du sphinx liée au rubis. - cweiske
J'ai utilisé l'option @reboot cron pour écrire le fichier cron-env. Vous pouvez ensuite le laisser dans la crontab et il ne sera réécrit qu'au démarrage du système. Cela simplifie un peu la tâche car vous n'avez pas à ajouter / supprimer de lignes. - Michael Barton


Comme crontab ne fait pas le travail, vous manipulerez son contenu:

crontab -l | grep -v '^#' | cut -f 6- -d ' ' | while read CMD; do eval $CMD; done

Ce qu'il fait :

  • liste les travaux crontab
  • supprimer les lignes de commentaire
  • supprimer la configuration de la crontab
  • puis lancez-les un à un

14
2017-08-19 19:45



Cela ne se fait pas nécessairement dans le même environnement que cron, cependant, et je pensais qu'il ne voulait tester qu'un seul d'entre eux. - Falcon Momot
correct, je me suis trompé ... Il ne fait que lancer les travaux mais pas comme cron le ferait! - Django Janny
toujours une solution géniale +1 - Eric Uldall


Par défaut, avec la plupart des démons cron par défaut que j'ai vus, il n'y a tout simplement aucun moyen de dire à cron de fonctionner ici et maintenant. Si vous utilisez anacron, il est peut-être possible d’exécuter une instance distincte au premier plan.

Si vos scripts ne fonctionnent pas correctement, vous ne prenez pas en compte le fait que

  • le script est exécuté en tant qu'utilisateur particulier
  • cron a un environnement restreint (la manifestation la plus évidente est un chemin différent).

De crontab (5):

Plusieurs variables d'environnement sont définies   up automatiquement par le cron (8)   démon. SHELL est défini sur / bin / sh, et   LOGNAME et HOME sont définis à partir du   Ligne / etc / passwd du fichier de travail de la crontab   propriétaire. PATH est défini sur "/ usr / bin: / bin".   HOME, SHELL et PATH peuvent être   remplacé par les paramètres du   crontab; LOGNAME est l'utilisateur que le   travail est en cours d'exécution à partir, et peut ne pas être   modifié.

En général, PATH est le plus gros problème, vous devez donc:

  • Définissez explicitement le PATH dans le script, lors du test, sur / usr / bin: / bin. Vous pouvez le faire en bash avec export PATH = "/ usr / bin: / bin"
  • Définissez explicitement le bon PATH que vous voulez en haut de la crontab. par exemple. PATH = "/ usr / bin: / bin: / usr / local / bin: / usr / sbin: / sbin"

Si vous devez exécuter le script sous un autre utilisateur sans shell (par exemple, www-data), utilisez sudo:

sudo -u www-data /path/to/crontab-script.sh

La première chose à tester avant tout cela, bien sûr, est que votre script fait ce qu'il est censé faire depuis la ligne de commande. Si vous ne pouvez pas l'exécuter depuis la ligne de commande, cela ne fonctionnera évidemment pas avec cron.


5
2017-11-18 14:27



Merci pour la réponse approfondie. Je suis conscient des deux problèmes liés à l'exécution en tant qu'utilisateur particulier et dans un environnement particulier. En tant que tel, j'ai formulé ma propre réponse, que je vais maintenant publier ... - Pistos
Les caractères d'échappement sont des raisons valables pour que le travail ne soit pas exécuté - Joe Phillips


Eh bien, l'utilisateur est le même que celui que vous avez mis dans l'entrée de la crontab (ou la crontab dans laquelle vous l'avez insérée, alternativement), c'est donc une évidence. crontab(5) devrait vous donner la liste des variables d'environnement définies, il n'y en a que quelques-unes.


1
2017-11-18 14:04



En d'autres termes, vous dites qu'il n'y a aucun moyen de le faire? Seulement des solutions de contournement "assez proches"? - Pistos
Non, je dis que vous pouvez le faire en utilisant les informations fournies dans ma réponse. - womble♦


Dans la plupart des crontabs comme par exemple vixie-cron vous pouvez placer des variables dans la crontab elle-même, puis utiliser / usr / bin / env pour vérifier si cela a fonctionné. De cette façon, vous pouvez faire fonctionner votre script dans crontab une fois que vous avez découvert ce qui ne va pas avec le script run-as-cron.

SHELL=/bin/bash
LANG=en
FASEL=BLA

* * * * *   /usr/bin/env > /home/username/cron-env

1
2017-10-27 06:52





Le script de Marco n'a pas fonctionné pour moi pour une raison quelconque. Je n'avais pas le temps de déboguer, alors j'ai écrit un script Python qui fait la même chose. C'est plus long, mais: premièrement, cela fonctionne pour moi et deuxièmement, je le trouve plus facile à comprendre. Remplacez "/ tmp / cron-env" par l'emplacement où vous avez enregistré votre environnement. C'est ici:

#!/usr/bin/env python
from __future__ import division, print_function

import sys
import os

def main():
    if len(sys.argv) != 2 or sys.argv[1] in ('-h', '--help'):
        print("Usage: {} CMD\n"
              "Run a command as cron would. Note that CMD must be quoted to be only one argument."
              .format(sys.argv[0]))
        sys.exit(1)
    _me, cmd = sys.argv
    env = dict(line.strip().split('=', 1) for line in open('/tmp/cron-env'))
    sh = env['SHELL']
    os.execvpe(sh, [sh, '-c', cmd], env)

if __name__ == '__main__':
    main()

1
2017-12-24 08:48





La solution de Marco n'a pas fonctionné pour moi, mais le script python de Noam a fonctionné. Voici une légère modification du script de Marco qui l'a fait fonctionner pour moi:

#!/bin/sh
. "$1"
exec /usr/bin/env -i "$SHELL" -c "set -a;. $1; $2"

L'ajouté set -a variables d'exportation définies dans le script $ 1 et mises à la disposition de la commande $ 2

p.s. Le python de Noam fonctionnait, car il "exportait" l'environnement vers le processus enfant.


1
2018-05-11 05:05