Tester un travail hebdomadaire cron [fermé]

237

J'ai un #!/bin/bashfichier dans le répertoire cron.week.

Existe-t-il un moyen de tester si cela fonctionne? Je ne peux pas attendre 1 semaine

Je suis sur Debian 6 avec root

dynamique
la source
4
Vous ne pouvez pas simplement tester le script en l'exécutant sur la ligne de commande?
Frédéric Hamidi
5
ajoutez simplement une entrée distincte dans votre crontabqui exécute votre fichier toutes les quelques minutes, voyez si les résultats attendus sont là, puis supprimez l'entrée de test de votre crontab. trycrontab -e
davin
61
Non, l'exécuter à partir de la ligne de commande n'est pas un bon moyen. Le simple fait d'exécuter le script à partir de la ligne de commande ne garantit pas qu'il sera même exécuté comme le même utilisateur lorsqu'il était exécuté à partir de cron. Même s'il s'exécute sous le même utilisateur, vous ne pouvez jamais être sûr que tout le reste sera le même. Les scripts qui fonctionnent à partir de la ligne de commande peuvent échouer pour toutes sortes de raisons lorsqu'ils sont exécutés à partir de cron.
andynormancx
8
"toutes sortes" peut être légèrement hyperbolique ... les autorisations et les variables d'environnement sont les deux qui viennent à l'esprit, vous pouvez facilement avoir différentes autres conditions initiales comme les alias
andynormancx
3
Je viens de tester un nouveau travail cron, je vais ajouter un autre élément à "toutes sortes". Si vous avez des éléments dans bash_profile, ils ne sont pas exécutés une seule fois dans un travail cron, tandis que le test du travail à partir de la ligne de commande fonctionne parfaitement. Tester les tâches cron sur la ligne de commande standard n'est pas du tout un bon test.
andynormancx

Réponses:

233

Faites ce que fait cron, exécutez ce qui suit root:

run-parts -v /etc/cron.weekly

... ou le suivant si vous recevez l'erreur "Pas un répertoire: -v":

run-parts /etc/cron.weekly -v

L'option -vimprime les noms de script avant leur exécution.

NNRooth
la source
4
Si j'utilise l'option -v, elle affiche l'erreur "Pas un répertoire: -v", il n'y a pas de page de manuel pour cette commande dans mon système, -v signifie verbeux non? J'utilise Centos 6.4
max
3
Pour éviter l'erreur "Pas un répertoire", j'ai dû le faire à la place: run-parts /etc/cron.weekly -v
Craig Hyatt
22
Mais cela ne prend pas en compte les variables d'environnement qui pourraient être définies dans le crontab
fcurella
34
run-partsexécute simplement les scripts d'un répertoire donné. Rien à voir avec cron.
Nicolas
23
Cela n'aurait vraiment pas dû être voté et accepté, au-delà de l'exécution du script, cela ne vous dit pas si le script fonctionnera réellement lorsqu'il sera exécuté à partir de cron. Utilisez l'excellent script crontest dans l'une des autres réponses à cette question.
andynormancx
87

Un peu au-delà de la portée de votre question ... mais voici ce que je fais.

Le "comment puis-je tester un travail cron?" La question est étroitement liée à "comment puis-je tester des scripts qui s'exécutent dans des contextes non interactifs lancés par d'autres programmes?" Dans cron, le déclencheur est une condition temporelle, mais beaucoup d'autres fonctionnalités * nix lancent des scripts ou des fragments de script de manière non interactive, et souvent les conditions dans lesquelles ces scripts s'exécutent contiennent quelque chose d'inattendu et provoquent des ruptures jusqu'à ce que les bogues soient triés. (Voir aussi: https://stackoverflow.com/a/17805088/237059 )

Il est utile d'avoir une approche générale de ce problème.

L'une de mes techniques préférées consiste à utiliser un script que j'ai écrit appelé « crontest ». Il lance la commande cible dans une session d'écran GNU depuis cron, de sorte que vous pouvez vous attacher avec un terminal séparé pour voir ce qui se passe, interagir avec le script, même utiliser un débogueur.

Pour configurer cela, vous devez utiliser "toutes les étoiles" dans votre entrée crontab et spécifier crontest comme première commande sur la ligne de commande, par exemple:

* * * * * crontest /command/to/be/tested --param1 --param2

Alors maintenant, cron exécutera votre commande toutes les minutes, mais crontest s'assurera qu'une seule instance s'exécute à la fois. Si l'exécution de la commande prend du temps, vous pouvez effectuer un "screen -x" pour l'attacher et la regarder s'exécuter. Si la commande est un script, vous pouvez placer une commande "lecture" en haut pour la faire s'arrêter et attendre la fin de la pièce jointe à l'écran (appuyez sur Entrée après la pièce jointe)

Si votre commande est un script bash, vous pouvez le faire à la place:

* * * * * crontest --bashdb /command/to/be/tested --param1 --param2

Maintenant, si vous attachez avec "screen -x", vous serez confronté à une session bashdb interactive, et vous pourrez parcourir le code, examiner les variables, etc.

#!/bin/bash

# crontest
# See https://github.com/Stabledog/crontest for canonical source.

# Test wrapper for cron tasks.  The suggested use is:
#
#  1. When adding your cron job, use all 5 stars to make it run every minute
#  2. Wrap the command in crontest
#        
#
#  Example:
#
#  $ crontab -e
#     * * * * * /usr/local/bin/crontest $HOME/bin/my-new-script --myparams
#
#  Now, cron will run your job every minute, but crontest will only allow one
#  instance to run at a time.  
#
#  crontest always wraps the command in "screen -d -m" if possible, so you can
#  use "screen -x" to attach and interact with the job.   
#
#  If --bashdb is used, the command line will be passed to bashdb.  Thus you
#  can attach with "screen -x" and debug the remaining command in context.
#
#  NOTES:
#   - crontest can be used in other contexts, it doesn't have to be a cron job.
#       Any place where commands are invoked without an interactive terminal and
#       may need to be debugged.
#
#   - crontest writes its own stuff to /tmp/crontest.log
#
#   - If GNU screen isn't available, neither is --bashdb
#

crontestLog=/tmp/crontest.log
lockfile=$(if [[ -d /var/lock ]]; then echo /var/lock/crontest.lock; else echo /tmp/crontest.lock; fi )
useBashdb=false
useScreen=$( if which screen &>/dev/null; then echo true; else echo false; fi )
innerArgs="$@"
screenBin=$(which screen 2>/dev/null)

function errExit {
    echo "[-err-] $@" | tee -a $crontestLog >&2
}

function log {
    echo "[-stat-] $@" >> $crontestLog
}

function parseArgs {
    while [[ ! -z $1 ]]; do
        case $1 in
            --bashdb)
                if ! $useScreen; then
                    errExit "--bashdb invalid in crontest because GNU screen not installed"
                fi
                if ! which bashdb &>/dev/null; then
                    errExit "--bashdb invalid in crontest: no bashdb on the PATH"
                fi

                useBashdb=true
                ;;
            --)
                shift
                innerArgs="$@"
                return 0
                ;;
            *)
                innerArgs="$@"
                return 0
                ;;
        esac
        shift
    done
}

if [[ -z  $sourceMe ]]; then
    # Lock the lockfile (no, we do not wish to follow the standard
    # advice of wrapping this in a subshell!)
    exec 9>$lockfile
    flock -n 9 || exit 1

    # Zap any old log data:
    [[ -f $crontestLog ]] && rm -f $crontestLog

    parseArgs "$@"

    log "crontest starting at $(date)"
    log "Raw command line: $@"
    log "Inner args: $@"
    log "screenBin: $screenBin"
    log "useBashdb: $( if $useBashdb; then echo YES; else echo no; fi )"
    log "useScreen: $( if $useScreen; then echo YES; else echo no; fi )"

    # Were building a command line.
    cmdline=""

    # If screen is available, put the task inside a pseudo-terminal
    # owned by screen.  That allows the developer to do a "screen -x" to
    # interact with the running command:
    if $useScreen; then
        cmdline="$screenBin -D -m "
    fi

    # If bashdb is installed and --bashdb is specified on the command line,
    # pass the command to bashdb.  This allows the developer to do a "screen -x" to
    # interactively debug a bash shell script:
    if $useBashdb; then
        cmdline="$cmdline $(which bashdb) "
    fi

    # Finally, append the target command and params:
    cmdline="$cmdline $innerArgs"

    log "cmdline: $cmdline"


    # And run the whole schlock:
    $cmdline 

    res=$?

    log "Command result: $res"


    echo "[-result-] $(if [[ $res -eq 0 ]]; then echo ok; else echo fail; fi)" >> $crontestLog

    # Release the lock:
    9<&-
fi
Stabledog
la source
2
Génial, la solution parfaite. Toutes les autres techniques que j'avais essayées n'ont pas vraiment fonctionné, Crontest a résolu le problème facilement.
andynormancx
1
C'était bien plus que ce dont j'avais besoin mais +1 pour une excellente solution de toute façon; paramétrer le cron pour qu'il s'exécute plus souvent et vider la sortie vers / tmp était assez bon pour détecter mon problème.
jcollum
2
Cool. Oui, aucune raison de tirer le bulldozer si vous avez juste besoin d'une pelle à main :)
Stabledog
2
Super truc. Note sur mac que je devais brew tap discoteq/discoteq; brew install flockpuis modifier le script à utiliser/usr/local/bin/flock
Claudiu
1
belle utilité! Très utile pour diagnostiquer les problèmes d'authentification dans des contextes non interactifs.
Eric Blum
44

Après avoir dérangé avec des choses dans cron qui n'étaient pas instantanément compatibles, j'ai trouvé que l'approche suivante était agréable pour le débogage:

crontab -e

* * * * * /path/to/prog var1 var2 &>>/tmp/cron_debug_log.log

Cela exécutera la tâche une fois par minute et vous pouvez simplement regarder dans le /tmp/cron_debug_log.logfichier pour comprendre ce qui se passe.

Ce n'est pas exactement le "job de pompier" que vous recherchez peut-être, mais cela m'a beaucoup aidé lors du débogage d'un script qui ne fonctionnait pas dans cron au début.

Automatico
la source
9
Je recommanderais cette approche. Le problème dans la plupart des cas est que vous ne voyez pas l'erreur.
Yauhen Yakimovich
8
Ligne incorrecte, aucune distribution n'utilise bash pour le shell cron et donc & >> ne fonctionne pas. Je suggère d'utiliser à la >>/tmp/cron_debug_log.log 2>&1place
drizzt
1
Qu'entendez-vous par /path/to/prog- quel prog?
Nathan
3
Le programme que vous allez exécuter avec cron. Cela peut être usr/home/myFancyScript.shsimple lsou ce que vous voulez exécuter régulièrement.
Automatico
Cela a fonctionné pour moi. C'était la méthode la plus simple pour faire un test rapide pour vérifier si tout va bien
abhijit
25

J'utiliserais un fichier de verrouillage, puis définirais le travail cron pour qu'il s'exécute toutes les minutes. (utilisez crontab -e et * * * * * / path / to / job) De cette façon, vous pouvez continuer à éditer les fichiers et chaque minute ils seront testés. De plus, vous pouvez arrêter le cronjob en touchant simplement le fichier de verrouillage.

    #!/bin/sh
    if [ -e /tmp/cronlock ]
    then
        echo "cronjob locked"
        exit 1
    fi

    touch /tmp/cronlock
    <...do your regular cron here ....>
    rm -f /tmp/cronlock
Dave Fernholz
la source
4
Vous pouvez également utiliser à flock(1)partir du shell; voir man 1 flock. Assez pratique pour de telles utilisations car il fournit un blocage automatique.
Craig Ringer
5

Qu'en est-il de le mettre cron.hourly, d'attendre la prochaine exécution de tâches cron horaires, puis de le supprimer? Cela l'exécuterait une fois dans l'heure, et dans l'environnement cron. Vous pouvez également exécuter ./your_script, mais cela n'aura pas le même environnement que sous cron.

Jeremiah Willcock
la source
c'est à peu près la même chose que la réponse de @ Cort3z, avec moins de détails
jcollum
5

Aucune de ces réponses ne correspondait à ma situation spécifique, à savoir que je voulais exécuter une tâche cron spécifique, une seule fois, et l'exécuter immédiatement.

Je suis sur un serveur Ubuntu et j'utilise cPanel pour configurer mes tâches cron.

J'ai simplement noté mes paramètres actuels, puis les ai modifiés dans une minute. Lorsque j'ai corrigé un autre bug, je l'ai juste modifié à nouveau dans une minute. Et quand j'ai fini, je viens de réinitialiser les paramètres à leur niveau antérieur.

Exemple: Il est 16h34 en ce moment, alors j'ai mis 35 16 * * *, pour qu'il fonctionne à 16h35.

Cela a fonctionné comme un charme, et le plus que j'ai jamais dû attendre était un peu moins d'une minute.

Je pensais que c'était une meilleure option que certaines des autres réponses parce que je ne voulais pas exécuter tous mes crons hebdomadaires, et je ne voulais pas que le travail s'exécute toutes les minutes. Il me faut quelques minutes pour résoudre les problèmes avant de pouvoir le tester à nouveau. J'espère que cela aide quelqu'un.

Ben C
la source
Pourquoi utiliseriez-vous cron pour exécuter "une seule fois et l'exécuter immédiatement"? Il semble que vous feriez mieux de simplement exécuter le script directement.
Ian Hunter
4

En plus de cela, vous pouvez également utiliser:

http://pypi.python.org/pypi/cronwrap

pour envelopper votre cron pour vous envoyer un e-mail en cas de succès ou d'échec.

Low Kian Seong
la source
10
Cron ne transmet-il pas déjà de courrier électronique et de sortie du script lors de l'exécution?
Erik
Cron envoie un e-mail à l'utilisateur, et généralement, pour la plupart des tâches cron, l'utilisateur est uniquement root ou un service non interactif, de sorte que vous ne voyez jamais les e-mails. C'est ainsi que les serveurs se remplissent lorsqu'une erreur déclenche un énorme flot d'e-mails et qu'ils rebondissent à la racine.
dragon788
3

La solution que j'utilise est la suivante:

  1. Modifiez crontab (utilisez la commande: crontab -e) pour exécuter le travail aussi souvent que nécessaire (toutes les 1 minute ou 5 minutes)
  2. Modifiez le script shell qui doit être exécuté à l'aide de cron pour imprimer la sortie dans un fichier (par exemple: echo "Working fine" >>
    output.txt)
  3. Vérifiez le fichier output.txt à l'aide de la commande: tail -f output.txt, qui imprimera les derniers ajouts dans ce fichier, et vous pourrez ainsi suivre l'exécution du script
Abhilash
la source
2

Je teste normalement en exécutant le travail que j'ai créé comme ceci:

Pour ce faire, il est plus facile d'utiliser deux terminaux.

exécuter le travail:

#./jobname.sh

aller à:

#/var/log and run 

exécutez ce qui suit:

#tailf /var/log/cron

Cela me permet de voir la mise à jour des journaux cron en temps réel. Vous pouvez également consulter le journal après l'avoir exécuté, je préfère le regarder en temps réel.

Voici un exemple de tâche cron simple. Exécution d'une mise à jour yum ...

#!/bin/bash
YUM=/usr/bin/yum
$YUM -y -R 120 -d 0 -e 0 update yum
$YUM -y -R 10 -e 0 -d 0 update

Voici la répartition:

La première commande mettra à jour yum lui-même et la prochaine appliquera les mises à jour système.

-R 120: définit la durée maximale pendant laquelle yum attendra avant d'exécuter une commande

-e 0: définit le niveau d'erreur sur 0 (plage de 0 à 10). 0 signifie imprimer uniquement les erreurs critiques dont vous devez être informé.

-d 0: définit le niveau de débogage sur 0 - augmente ou diminue la quantité de choses imprimées. (plage: 0 - 10).

-y: Supposons que oui; supposons que la réponse à toute question qui serait posée est oui

Après avoir créé le travail cron, j'ai exécuté la commande ci-dessous pour rendre mon travail exécutable.

#chmod +x /etc/cron.daily/jobname.sh 

J'espère que cela aide, Dorlack

Dorlack
la source
2
sudo run-parts --test /var/spool/cron/crontabs/

les fichiers de ce crontabs/répertoire doivent être exécutables par le propriétaire - octal700

source: man cronet NNRooths »

n611x007
la source
5
Deux coups. Premièrement: pour exécuter les choses car sudo utilise un environnement différent (variables définies). Ainsi, les bogues dans votre crontab pourraient fonctionner lorsqu'ils sont exécutés en tant que «sudo», mais ne fonctionneront pas lorsqu'ils sont exécutés en tant que «root» (et vice versa). Deuxièmement: 'man cron' ne me montre pas ces informations (ok, mon homme semble être spécifique à Debian) ... 'man run-parts' dit que --test n'exécute pas les scripts, mais affiche uniquement les noms de leur. Les scripts ne sont donc même pas testés. Une chose mineure: «exécutable par le propriétaire»: pour autant que je sache, seuls les cronjobs sont exécutés en tant que root.
Alex
-1

J'utilise Webmin parce que c'est un joyau de productivité pour quelqu'un qui trouve l'administration de la ligne de commande un peu intimidante et impénétrable.

Il existe un bouton «Enregistrer et exécuter maintenant» dans l'interface Web «Système> Cron Jobs planifiés> Modifier le Cron Job».

Il affiche la sortie de la commande et correspond exactement à ce dont j'avais besoin.

Kickaha
la source