Pregunta Ejecutar un trabajo cron de forma manual e inmediata


(Ya he leído ¿Cómo puedo probar un nuevo script cron?.)

Tengo un problema específico (el trabajo cron no parece ejecutarse o ejecutarse correctamente), pero el problema es general: me gustaría depurar los scripts que están programados. Soy consciente de que puedo configurar una línea * * * * * de crontab, pero esa no es una solución totalmente satisfactoria. Me gustaría poder ejecutar un trabajo cron desde la línea de comandos como si cron lo estuviera ejecutando (mismo usuario, mismas variables de entorno, etc.). ¿Hay alguna forma de hacer esto? Tener que esperar 60 segundos para probar los cambios de script no es práctico.


94
2017-11-18 13:55


origen


(lo siento no puedo agregar comentario) 0 30 16 20 *? * incluso si ejecuta el trabajo de esa manera, la idea general es proporcionar una salida de script para ver qué está mal a menos que el trabajo se escriba en un registro, esto es bastante inútil


Respuestas:


Esto es lo que hice, y parece funcionar en esta situación. Al menos, me muestra un error, mientras que se ejecuta desde la línea de comandos ya que el usuario no muestra el error.


Paso 1: Puse esta línea temporalmente en el crontab del usuario:

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

luego lo sacó una vez que el archivo fue escrito.

Paso 2: Me hice una pequeña secuencia de comandos de ejecución de cron que contiene:

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

Entonces, como el usuario en cuestión, pude

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

Esta solución, obviamente, podría ampliarse para hacer uso de sudo o similares para obtener más flexibilidad.

Espero que esto ayude a los demás.


73
2017-11-18 14:40



Esto no funciona para mí y me pregunto si lo hará para cualquiera que haya votado. 1) ¿Por qué estás usando bash? No se requiere aquí y podría no estar ubicado en /usr/bin. 2) El cat …/cron-env Salidas de varias líneas, lo que no funciona. Solo intenta ejecutar /usr/bin/env -i $(cat cron-env) echo $PATH en el terminal, genera el entorno literalmente en lugar de usarlo. 3) El entorno actual se filtra en el entorno cron emulado. Tratar: export foo=leaked; run-as-cron echo $foo. - Marco
@Marco Works en bash, que es lo que uso, ya que es un entorno mejor definido que sh. Utilizo todo, desde pdksh, ksh (varias versiones), bash y dash, por lo que soy muy consciente de las diferencias entre las implementaciones de "puro" de sh, incluso cuando me mantengo estrictamente en el subconjunto común de los idiomas. :-) - Max Murphy
@Marco 2. cat genera varias líneas, que funcionan, porque la sustitución de shell las colapsa en una sola línea, que puede verificar con echo $(cat cron-env ) | wc; su ejemplo de comando, /usr/bin/env -i $(cat cron-env) echo $PATH, sustitutos $PATH desde el shell que llama; en su lugar, debería invocar una subshell para sustituir en el subentorno, por ejemplo. /usr/bin/env -i $(cat cron-env) /bin/sh -c 'echo $PATH'. 3. Ha cometido el mismo error, sustituyendo de nuevo en el shell de llamada en lugar de en el subentorno - John Freeman


Presento una solución basada en la respuesta de Pistos, pero sin las fallas.

  • Agregue la siguiente línea al crontab, por ej. utilizando crontab -e

    * * * * *  /usr/bin/env > /home/username/cron-env
    
  • Cree un script de shell que ejecute un comando en el mismo entorno en el que se ejecutan los trabajos cron:

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

Utilizar:

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

p.ej.

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

Tenga en cuenta que el segundo argumento debe citarse si requiere un argumento. La primera línea del script carga un shell POSIX como intérprete. La segunda línea origina el archivo del entorno cron. Esto es necesario para cargar el shell correcto, que se almacena en la variable de entorno SHELL. Luego carga un entorno vacío (para evitar la pérdida de variables de entorno en el nuevo shell), inicia el mismo shell que se utiliza para cronjobs y carga las variables de entorno cron. Finalmente se ejecuta el comando.


34
2017-09-24 18:46



esto me ayudó a reproducir el error de carga de la esfinge relacionada con el rubí. - cweiske
Usé la opción cron @reboot para escribir el archivo cron-env. Luego puede dejarlo en el crontab y solo se volverá a escribir cuando se inicie el sistema. Lo hace un poco más sencillo ya que no tiene que agregar / eliminar líneas. - Michael Barton


Como crontab no hace el trabajo, tendrás que manipular su contenido:

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

Que hace :

  • listas de trabajos de crontab
  • eliminar líneas de comentarios
  • eliminar la configuración crontab
  • luego lanzarlos uno por uno

14
2017-08-19 19:45



Sin embargo, esto no necesariamente lo hace en el mismo entorno que lo haría cron, y pensé que quería probar solo uno de ellos. - Falcon Momot
correcto, me he equivocado ... ¡Solo ejecuta los trabajos pero no como lo haría cron! - Django Janny
sigue siendo una solución impresionante +1 - Eric Uldall


Por defecto, con la mayoría de los demonios cron predeterminados que he visto, simplemente no hay forma de decirle a cron que se ejecute aquí ahora mismo. Si está usando anacron, creo que es posible ejecutar una instancia separada en primer plano.

Si sus scripts no se ejecutan correctamente, entonces no está tomando en cuenta que

  • el script se ejecuta como un usuario particular
  • cron tiene un entorno restringido (la manifestación más obvia de esto es una ruta diferente).

Desde crontab (5):

Se establecen varias variables de entorno.   arriba automáticamente por el cron (8)   demonio. SHELL se establece en / bin / sh, y   LOGNAME y HOME se establecen desde el   / etc / passwd line del crontab's   propietario. PATH se establece en "/ usr / bin: / bin".   HOME, SHELL, y PATH pueden ser   anulado por la configuración en el   crontab; LOGNAME es el usuario que el   trabajo se está ejecutando desde, y no puede ser   cambiado

En general, PATH es el mayor problema, por lo que debe:

  • Establezca explícitamente el PATH dentro del script, mientras prueba, en / usr / bin: / bin. Puedes hacer esto en bash con export PATH = "/ usr / bin: / bin"
  • Establezca explícitamente el PATH adecuado que desee en la parte superior del crontab. p.ej. PATH = "/ usr / bin: / bin: / usr / local / bin: / usr / sbin: / sbin"

Si necesita ejecutar el script como otro usuario sin un shell (por ejemplo, www-data), use sudo:

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

Lo primero que hay que probar antes de todo eso, por supuesto, es que su script realmente hace lo que se supone que debe hacer desde la línea de comandos. Si no puede ejecutarlo desde la línea de comandos, obviamente no funcionará con cron.


5
2017-11-18 14:27



Gracias por la respuesta a fondo. Soy consciente de los dos problemas de la ejecución como usuario particular y con un entorno particular. Como tal, he formulado mi propia respuesta, que ahora publicaré ... - Pistos
Los caracteres de escape son una razón válida para que el trabajo no se ejecute - Joe Phillips


Bueno, el usuario es el mismo que el que pones en la entrada de crontab (o en cuyo crontab lo pones, alternativamente), así que eso es una obviedad. crontab(5) debería darle la lista de variables de entorno establecidas, solo hay unas pocas.


1
2017-11-18 14:04



En otras palabras, ¿estás diciendo que no hay manera de hacerlo? Sólo "lo suficientemente cerca" soluciones? - Pistos
No, estoy diciendo que puedes hacerlo usando la información que proporcioné en mi respuesta. - womble♦


En la mayoría de los crontabs como por ejemplo vixie-cron puede colocar variables en el propio crontab así y luego usar / usr / bin / env para verificar si funcionó. De esta manera, puede hacer que su script funcione en crontab una vez que haya averiguado cuál es el problema con el script de ejecución como cron.

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

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

1
2017-10-27 06:52





El guión de Marco no me funcionó por alguna razón. No tuve tiempo de depurar, así que escribí un script de Python que hace lo mismo. Es más largo, pero: primero, funciona para mí, y segundo, me resulta más fácil de entender. Cambie "/ tmp / cron-env" a donde guardó su entorno. Aquí está:

#!/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