Probar un trabajo cron semanal [cerrado]

237

Tengo un #!/bin/basharchivo en el directorio cron.week.

¿Hay alguna forma de probar si funciona? No puedo esperar 1 semana

Estoy en Debian 6 con root

dinámica
fuente
44
¿No puedes probar el script ejecutándolo en la línea de comando?
Frédéric Hamidi
55
simplemente agregue una entrada separada en su crontabarchivo que ejecute su archivo cada pocos minutos, vea si los resultados esperados están ahí y luego elimine la entrada de prueba de su crontab. probarcrontab -e
davin
61
No, ejecutarlo desde la línea de comandos no es una buena manera. Simplemente ejecutar el script desde la línea de comandos no garantiza que incluso se ejecutará como el mismo usuario cuando se ejecutó desde cron. Incluso si se ejecuta como el mismo usuario, nunca puede estar seguro de si todo lo demás será igual. Los scripts que funcionan desde la línea de comando pueden fallar por todo tipo de razones cuando se ejecutan desde cron.
andynormancx
8
"todo tipo" pueden sido ligeramente hiperbólica ... permisos y variables de entorno son los dos que vienen a la mente, que podría fácilmente tener diversas otras condiciones iniciales como alias aunque
andynormancx
3
Acabo de terminar de probar un nuevo trabajo cron, agregaré otro elemento a "todo tipo". Si tiene cosas en bash_profile, no se ejecutan una vez en un trabajo cron, mientras que probar el trabajo desde la línea de comandos funciona perfectamente. Probar trabajos cron en la línea de comandos estándar no es una buena prueba en absoluto.
andynormancx

Respuestas:

233

Simplemente haga lo que hace cron, ejecute lo siguiente como root:

run-parts -v /etc/cron.weekly

... o el siguiente si recibe el error "No es un directorio: -v":

run-parts /etc/cron.weekly -v

La opción -vimprime los nombres de script antes de que se ejecuten.

NNRooth
fuente
44
Si uso la opción -v que muestra el error "No es un directorio: -v", no hay página de manual para este comando en mi sistema, -v significa detallado, ¿verdad? Estoy usando centos 6.4
máximo
3
Para evitar el error "No es un directorio", tuve que hacer esto en su lugar: run-parts /etc/cron.weekly -v
Craig Hyatt
22
Pero esto no tiene en cuenta las variables de entorno que podrían establecerse en el crontab
fcurella
34
run-partssolo ejecuta los scripts de un directorio dado. Nada que ver con cron.
Nicolas
23
Esto realmente no debería haber sido votado y aceptado, más allá de ejecutar el script, no hace nada para decirte si el script realmente funcionará cuando se ejecute desde cron. Utilice el excelente script crontest en una de las otras respuestas a esta pregunta.
andynormancx
87

Un poco más allá del alcance de su pregunta ... pero esto es lo que hago.

El "¿cómo pruebo un trabajo cron?" la pregunta está estrechamente relacionada con "¿cómo pruebo los scripts que se ejecutan en contextos no interactivos lanzados por otros programas?" En cron, el desencadenante es una condición de tiempo, pero muchas otras instalaciones * nix lanzan guiones o fragmentos de guiones de manera no interactiva, y a menudo las condiciones en que se ejecutan esos guiones contienen algo inesperado y causan roturas hasta que se solucionen los errores. (Ver también: https://stackoverflow.com/a/17805088/237059 )

Es útil tener un enfoque general de este problema.

Una de mis técnicas favoritas es usar un script que escribí llamado ' crontest '. Inicia el comando de destino dentro de una sesión de pantalla GNU desde cron, para que pueda adjuntarlo con un terminal separado para ver qué está pasando, interactuar con el script e incluso usar un depurador.

Para configurar esto, usaría "todas las estrellas" en su entrada crontab, y especificaría crontest como el primer comando en la línea de comando, por ejemplo:

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

Entonces, cron ejecutará su comando cada minuto, pero crontest se asegurará de que solo se ejecute una instancia a la vez. Si el comando tarda en ejecutarse, puede hacer una "pantalla -x" para adjuntarlo y verlo ejecutarse. Si el comando es un script, puede poner un comando de "lectura" en la parte superior para que se detenga y espere a que se complete el archivo adjunto de la pantalla (presione enter después de adjuntar)

Si su comando es un script bash, puede hacer esto en su lugar:

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

Ahora, si se adjunta con "screen -x", se enfrentará a una sesión bashdb interactiva, y puede recorrer el código, examinar 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
fuente
2
Impresionante, la solución perfecta. Todas las otras técnicas que había probado no funcionaron realmente, crontest resolvió el problema fácilmente.
andynormancx
1
Esto era mucho más de lo que necesitaba, pero de todos modos +1 para una gran solución; configurar el cron para que se ejecute con más frecuencia y volcar la salida a / tmp fue lo suficientemente bueno como para detectar mi problema.
jcollum
2
Frio. Sí, no hay razón para encender la excavadora si solo necesitas una pala de mano :)
Stabledog
2
Buena cosa. Nota sobre mac tuve que brew tap discoteq/discoteq; brew install flocky luego modificar el script para usar/usr/local/bin/flock
Claudiu
1
buena utilidad! Muy útil para diagnosticar problemas de autenticación en contextos no interactivos.
Eric Blum
44

Después de jugar con algunas cosas en cron que no eran compatibles al instante, descubrí que el siguiente enfoque era bueno para la depuración:

crontab -e

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

Esto ejecutará la tarea una vez por minuto y simplemente puede mirar en el /tmp/cron_debug_log.logarchivo para descubrir qué está sucediendo.

No es exactamente el "trabajo de fuego" que podría estar buscando, pero esto me ayudó mucho al depurar un script que al principio no funcionaba en cron.

Automatico
fuente
99
Yo recomendaría este enfoque. El problema en la mayoría de los casos es que no ves el error.
Yauhen Yakimovich
8
Línea incorrecta, ninguna distribución usa bash para cron shell y por lo tanto & >> no funciona. Sugiero usar en su >>/tmp/cron_debug_log.log 2>&1lugar
drizzt
1
¿Qué quieres decir con /path/to/prog- qué programa?
Nathan
3
El programa que vas a ejecutar con cron. Esto puede ser usr/home/myFancyScript.sho puede ser simple ls, o lo que quieras ejecutar regularmente.
Automatico
Esto funcionó para mí. Fue el método más fácil para hacer una prueba rápida para verificar si todo está bien
abhijit
25

Usaría un archivo de bloqueo y luego configuraría el trabajo cron para que se ejecutara cada minuto. (use crontab -e y * * * * * / path / to / job) De esa manera puede seguir editando los archivos y cada minuto serán probados. Además, puede detener el cronjob tocando el archivo de bloqueo.

    #!/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
fuente
44
También puede usar flock(1)desde el shell; ver man 1 flock. Muy útil para tales usos, ya que proporciona bloqueo automático.
Craig Ringer el
5

¿Qué hay de ponerlo cron.hourly, esperar hasta la próxima ejecución de trabajos cron por hora y luego eliminarlo? Eso lo ejecutaría una vez dentro de una hora, y en el entorno cron. También puede ejecutar ./your_script, pero eso no tendrá el mismo entorno que bajo cron.

Jeremiah Willcock
fuente
esto es más o menos lo mismo que la respuesta de @ Cort3z, con menos detalles
jcollum
5

Ninguna de estas respuestas se ajusta a mi situación específica, que era que quería ejecutar un trabajo cron específico, solo una vez, y ejecutarlo de inmediato.

Estoy en un servidor Ubuntu y uso cPanel para configurar mis trabajos cron.

Simplemente escribí mi configuración actual, y luego la edité para que sea un minuto a partir de ahora. Cuando arreglé otro error, lo volví a editar a un minuto a partir de ahora. Y cuando terminé, simplemente restablecí la configuración a como estaba antes.

Ejemplo: Son las 4:34 pm en este momento, así que puse 35 16 * * *, para que se ejecute a las 16:35.

Funcionó de maravilla, y lo máximo que tuve que esperar fue un poco menos de un minuto.

Pensé que esta era una mejor opción que algunas de las otras respuestas porque no quería ejecutar todos mis crons semanales, y no quería que el trabajo se ejecutara cada minuto. Me lleva unos minutos solucionar los problemas antes de estar listo para volver a probarlo. Esperemos que esto ayude a alguien.

Ben C
fuente
¿Por qué usarías cron para ejecutar "solo una vez y ejecutarlo de inmediato"? Parece que sería mejor simplemente ejecutar el script directamente.
Ian Hunter
4

Aparte de eso, también puedes usar:

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

para terminar su cron para enviarle un correo electrónico en caso de éxito o fracaso.

Low Kian Seong
fuente
10
¿Cron ya no envía por correo electrónico y genera el script después de la ejecución?
Erik
Cron envía un correo electrónico al usuario y, por lo general, el usuario para la mayoría de los trabajos cron es un usuario root o un usuario de servicio no interactivo, por lo que nunca verá los correos electrónicos. Así es como se llenan los servidores cuando un error desencadena una gran avalancha de correos electrónicos y rebotan a la raíz.
dragon788
3

La solución que estoy usando es la siguiente:

  1. Edite crontab (use el comando: crontab -e) para ejecutar el trabajo con la frecuencia que sea necesaria (cada 1 minuto o 5 minutos)
  2. Modifique el script de shell que debe ejecutarse usando cron para imprimir la salida en algún archivo (por ejemplo: echo "Working fine" >>
    output.txt)
  3. Verifique el archivo output.txt con el comando: tail -f output.txt, que imprimirá las últimas adiciones en este archivo, y así podrá rastrear la ejecución del script
Abhilash
fuente
2

Normalmente pruebo ejecutando el trabajo que creé así:

Es más fácil usar dos terminales para hacer esto.

ejecutar trabajo:

#./jobname.sh

ir:

#/var/log and run 

ejecuta lo siguiente:

#tailf /var/log/cron

Esto me permite ver la actualización de los registros cron en tiempo real. También puede revisar el registro después de ejecutarlo, prefiero verlo en tiempo real.

Aquí hay un ejemplo de un trabajo cron simple. Ejecutando una actualización 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

Aquí está el desglose:

El primer comando actualizará yum y luego aplicará las actualizaciones del sistema.

-R 120: establece la cantidad máxima de tiempo que esperará antes de ejecutar un comando

-e 0: establece el nivel de error en 0 (rango 0-10). 0 significa imprimir solo los errores críticos sobre los que se le debe informar.

-d 0: establece el nivel de depuración en 0: aumenta o disminuye la cantidad de elementos que se imprimen. (rango: 0-10).

-y: Supongamos que sí; supongamos que la respuesta a cualquier pregunta que se haga es sí

Después de construir el trabajo cron, ejecuté el siguiente comando para hacer que mi trabajo sea ejecutable.

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

Espero que esto ayude, Dorlack

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

los archivos en ese crontabs/directorio deben ser ejecutables por el propietario - octal700

fuente: man crony NNRooth's

n611x007
fuente
55
Dos tings Primero: Para ejecutar cosas como sudo se usa un entorno diferente (variables definidas). Entonces, los errores en su crontab podrían funcionar cuando se ejecutan como 'sudo', pero no funcionarán cuando se ejecutan como 'root' (y viceversa). Segundo: 'man cron' no me muestra esta información (ok, mi hombre parece ser específico de Debian) ... 'man run-parts' dice que --test no ejecuta los scripts, solo imprime los nombres de ellos. Por lo tanto, los scripts ni siquiera se prueban. Una cosa menor: 'ejecutable por el propietario': por lo que sé, los cronjobs solo se ejecutan como root.
Alex
-1

Estoy usando Webmin porque es una joya de productividad para alguien que encuentra la administración de la línea de comandos un poco desalentadora e impenetrable.

Hay un botón "Guardar y ejecutar ahora" en la interfaz web "Sistema> Trabajos cronológicos programados> Editar trabajo cronológico".

Muestra el resultado del comando y es exactamente lo que necesitaba.

Kickaha
fuente