¿Por qué mi crontab no funciona y cómo puedo solucionarlo?

226

Esta es una pregunta canónica sobre el uso de cron y crontab.

Te han dirigido aquí porque la comunidad está bastante segura de que la respuesta a tu pregunta se puede encontrar a continuación. Si su pregunta no se responde a continuación, las respuestas lo ayudarán a recopilar información que ayudará a la comunidad a ayudarlo. Esta información debe ser editada en su pregunta original.

La respuesta para ' ¿Por qué mi crontab no funciona y cómo puedo solucionarlo? 'se puede ver a continuación. Esto se dirige al cronsistema con el crontab resaltado.

Eric Leschinski
fuente
2
Este es un gran engaño de Razones por las cuales crontab no funciona en AskUbuntu.
Dan Dascalescu
1
@DanDascalescu Parece que Eric necesita obtener más reputación
soy la persona más estúpida el
1
Acabo de unirme a Server Fault SE (solo 101 rep), ¡pero me encantaría darle a esta pregunta un -1! ¿Se hizo esta pregunta solo para obtener representante? @IamtheMostStupidPerson Totalmente de acuerdo contigo ...
Holyprogrammer
La ideología occidental en estos padawans de 13 años es a la vez libro de texto y cegador, como una supernova. Para responder ambas preguntas: sí, lo hice por el representante, y sí, Eric necesita obtener más reputación. ¿Cuánto más representante necesito? Más. youtu.be/IaDt9T7BF38?t=262
Eric Leschinski

Respuestas:

317

Cómo solucionar todos los problemas / problemas relacionados con crontab (Linux)


Esta es una wiki comunitaria , si notas algo incorrecto con esta respuesta o tienes información adicional, edítala.


Primero, terminología básica:

  • cron (8) es el demonio que ejecuta comandos programados.
  • crontab (1) es el programa utilizado para modificar los archivos de usuario crontab (5).
  • crontab (5) es un archivo por usuario que contiene instrucciones para cron (8).

A continuación, educación sobre cron:

Cada usuario en un sistema puede tener su propio archivo crontab. La ubicación de los archivos crontab raíz y de usuario depende del sistema, pero generalmente se encuentran a continuación /var/spool/cron.

Hay un /etc/crontabarchivo de todo el sistema, el /etc/cron.ddirectorio puede contener fragmentos de crontab que también son leídos y accionados por cron. Algunas distribuciones de Linux (por ejemplo, Red Hat) también tienen /etc/cron.{hourly,daily,weekly,monthly}directorios, scripts dentro de los cuales se ejecutarán cada hora / día / semana / mes, con privilegios de root.

root siempre puede usar el comando crontab; Los usuarios habituales pueden o no tener acceso. Cuando edita el archivo crontab con el comando crontab -ey lo guarda, crond verifica su validez básica pero no garantiza que su archivo crontab esté formado correctamente. Hay un archivo llamado cron.denyque especificará qué usuarios no pueden usar cron. La cron.denyubicación del archivo depende del sistema y se puede eliminar, lo que permitirá a todos los usuarios usar cron.

Si la computadora no está encendida o el demonio crond no se está ejecutando, y la fecha / hora de ejecución de un comando ha pasado, crond no se pondrá al día y ejecutará consultas pasadas.

Crontab particulares, cómo formular un comando:

Un comando crontab está representado por una sola línea. No puede usar \para extender un comando sobre varias líneas. El #signo hash ( ) representa un comentario que significa que cualquier cosa en esa línea es ignorada por cron. Los espacios en blanco iniciales y las líneas en blanco se ignoran.

Sea MUY cuidadoso cuando use el %signo de porcentaje ( ) en su comando. A menos que se \%escapen, se convierten en nuevas líneas y todo después de que el primer no escapado %se pase a su comando en stdin.

Hay dos formatos para los archivos crontab:

  • Crontabs de usuario

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  *   command to be executed
    
  • Sistema ancho /etc/crontaby /etc/cron.dfragmentos

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    

Tenga en cuenta que este último requiere un nombre de usuario. El comando se ejecutará como el usuario nombrado.

Los primeros 5 campos de la línea representan los tiempos en que se debe ejecutar el comando. Puede usar números o, si corresponde, nombres de día / mes en la especificación de tiempo.

  • Los campos están separados por espacios o pestañas.
  • Se ,utiliza una coma ( ) para especificar una lista, por ejemplo, 1,4,6,8, que significa ejecutar en 1,4,6,8.
  • Los rangos se especifican con un guión ( -) y se pueden combinar con listas, por ejemplo, 1-3,9-12, lo que significa entre 1 y 3 y luego entre 9 y 12.
  • El /personaje se puede utilizar para introducir un paso, por ejemplo, 2/5, lo que significa comenzar en 2 y luego cada 5 (2,7,12,17,22 ...). No terminan más allá del final.
  • Un asterisco ( *) en un campo significa el rango completo para ese campo (por ejemplo, 0-59para el campo de minutos).
  • Los rangos y los pasos se pueden combinar, por ejemplo, */2significa comenzar desde el mínimo para el campo relevante y luego cada 2, por ejemplo, 0 por minutos (0,2 ... 58), 1 por meses (1,3 ... 11), etc.

Depuración de comandos cron

¡Revisa el correo!

De forma predeterminada, cron enviará cualquier salida del comando al usuario que está ejecutando el comando como. Si no hay salida, no habrá correo. Si desea que cron envíe correo a una cuenta diferente, puede configurar la variable de entorno MAILTO en el archivo crontab, por ejemplo

[email protected]
1 2 * * * /path/to/your/command

Capture la salida usted mismo

Puede redirigir stdout y stderr a un archivo. La sintaxis exacta para capturar resultados puede variar según el shell que esté utilizando el cron. Aquí hay dos ejemplos que guardan todos los resultados en un archivo en /tmp/mycommand.log:

1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1

Mira los troncos

Cron registra sus acciones a través de syslog, que (dependiendo de su configuración) a menudo van /var/log/cronao /var/log/syslog.

Si es necesario, puede filtrar las declaraciones cron con, por ejemplo,

grep CRON /var/log/syslog 

Ahora que hemos repasado los conceptos básicos de cron, dónde están los archivos y cómo usarlos, veamos algunos problemas comunes.

Comprueba que cron se está ejecutando

Si cron no se está ejecutando, sus comandos no se programarán ...

ps -ef | grep cron | grep -v grep

debería conseguirte algo como

root    1224   1  0 Nov16 ?    00:00:03 cron

o

root    2018   1  0 Nov14 ?    00:00:06 crond

Si no, reinícielo

/sbin/service cron start

o

/sbin/service crond start

Puede haber otros métodos; usa lo que tu distribución proporciona.

cron ejecuta su comando en un entorno restringido.

Es probable que las variables de entorno disponibles sean muy limitadas. Por lo general, sólo obtendrá un par de variables definidas, tales como $LOGNAME, $HOME, y $PATH.

De particular interés es que PATHestá restringido a /bin:/usr/bin. La gran mayoría de los problemas de "mi script cron no funciona" son causados ​​por esta ruta restrictiva . Si su comando está en una ubicación diferente, puede resolver esto de dos maneras:

  1. Proporcione la ruta completa a su comando.

    1 2 * * * /path/to/your/command
    
  2. Proporcione una RUTA adecuada en el archivo crontab

    PATH=/usr:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

Si su comando requiere otras variables de entorno, también puede definirlas en el archivo crontab.

cron ejecuta su comando con cwd == $ HOME

Independientemente de dónde resida el programa que ejecute en el sistema de archivos, el directorio de trabajo actual del programa cuando cron lo ejecute será el directorio de inicio del usuario . Si accede a los archivos en su programa, deberá tener esto en cuenta si usa rutas relativas, o (preferiblemente) solo usa rutas completamente calificadas en todas partes, y ahorrará a todos mucha confusión.

El último comando en mi crontab no se ejecuta

Cron generalmente requiere que los comandos se terminen con una nueva línea. Edite su crontab; vaya al final de la línea que contiene el último comando e inserte una nueva línea (presione Intro).

Comprueba el formato crontab

No puede usar un crontab con formato de usuario crontab para / etc / crontab o los fragmentos en /etc/cron.d y viceversa. Un crontab formateado por el usuario no incluye un nombre de usuario en la sexta posición de una fila, mientras que un crontab formateado del sistema incluye el nombre de usuario y ejecuta el comando como ese usuario.

Puse un archivo en /etc/cron.{hourly,daily,weekly,monthly} y no se ejecuta

  • Verifique que el nombre del archivo no tenga una extensión vea run-parts
  • Asegúrese de que el archivo tenga permisos de ejecución.
  • Dígale al sistema qué usar cuando ejecute su secuencia de comandos (por ejemplo, poner #!/bin/shen la parte superior)

Errores relacionados con la fecha Cron

Si un usuario o una actualización del sistema, una zona horaria u otra cambiaron su fecha recientemente, crontab comenzará a comportarse de manera errática y exhibirá errores extraños, a veces funcionando, a veces no. Este es el intento de crontab para tratar de "hacer lo que quieras" cuando el tiempo cambia desde abajo. El campo "minuto" se volverá ineficaz después de cambiar la hora. En este escenario, solo se aceptarían asteriscos. Reinicie cron e inténtelo de nuevo sin conectarse a Internet (para que la fecha no tenga la posibilidad de restablecerse en uno de los servidores horarios).

Signos de porcentaje, de nuevo

Para enfatizar el consejo sobre los signos de porcentaje, aquí hay un ejemplo de lo que cron hace con ellos:

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

creará el archivo ~ / cron.out que contiene las 3 líneas

foo
bar
baz

Esto es particularmente intrusivo cuando se usa el datecomando. Asegúrese de escapar de los signos de porcentaje

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"
Eric Leschinski
fuente
Es posible que desee mencionar también en la sección 'entorno restringido' que LD_LIBRARY_PATH también puede necesitar tener directorios adicionales configurados en caso de que su tarea cron falle porque no puede encontrar bibliotecas compartidas.
DavidJ
tenga en cuenta que incluso puede escribir algo como esto: 35 1,5-23 / 2 * * * do_something en lugar de 35,1,5,7,9, .. * * * Además, este crontab.guru traduce las entradas que usted hace a lenguaje humano
Dennis Nolte
1
La captura de salida no funciona para mí, puede deberse a la shell sh. Creo que esto es más portátil: ... /path/to/your/command >/tmp/mycommand.log 2>&1
chus
esto funcionó para mí:sudo apt-get install postfix
jmunsch
¿cron job también depende de qué tan pesado es el archivo? Debido a que ejecuté hello world simple en python con cron, funcionó. Pero mi segundo código era un poco pesado y normalmente se ejecuta, pero con cron no está dando salida al archivo.
Devendra Bhat
22

Debian Linux y sus derivados (Ubuntu, Mint, etc.) tienen algunas peculiaridades que pueden impedir que se ejecuten sus trabajos cron; en particular, los archivos en /etc/cron.d, /etc/cron.{hourly,daily,weekly,monthly}deben:

  • ser propiedad de root
  • solo se puede escribir de raíz
  • no se puede escribir por grupo u otros usuarios
  • tener un nombre sin puntos '.' o cualquier otro carácter especial pero '-' y '_'.

El último lastima regularmente a los usuarios desprevenidos; en particular, cualquier secuencia de comandos en una de estas carpetas con el nombre whatever.sh, mycron.py, testfile.pl, etc va a no ser ejecutado, nunca.

En mi experiencia, este punto en particular ha sido, con mucho, la razón más frecuente para un trabajo temporal no ejecutable en Debian y derivados.

Ver man cronpara más detalles, si es necesario.

wazoox
fuente
19

Si sus cronjobs dejan de funcionar, verifique que su contraseña no haya expirado, ya que una vez que lo ha hecho, todos los trabajos cron se detienen.
Habrá mensajes /var/log/messagessimilares al siguiente que muestran problemas con la autenticación del usuario:

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)

Munkeh72
fuente
2
Acabo de recibir esto también (archivo de mensaje de error / var / log / syslog para mí). En mi caso, un cuadro DigitalOcean que, en el momento de la creación, restablecen la contraseña de root (opcionalmente) a otra, y aparentemente hasta que entras allí y la cambias, no se ejecutan todos los trabajos cron. Gorrón. Arreglar es algo asísudo -u root passwd
rogerdpack
12

Horarios poco frecuentes e irregulares

Cron se considera un planificador muy básico y la sintaxis no permite fácilmente que un administrador formule horarios un poco más poco comunes.

Considere el siguiente trabajo que comúnmente se explicaría como "ejecutar commandcada 5 minutos" :

*/5 * * * * /path/to/your/command

versus:

*/7 * * * * /path/to/your/command

que no siempre se ejecuta commandcada 7 minutos .

Recuerde que el /personaje puede usarse para introducir un paso, pero que los pasos no se ajustan más allá del final de una serie, por ejemplo, */7que coincide cada 7 minutos desde los minutos, 0-59 es decir, 0,7,14,21,28,35,42,49, 56 pero entre una hora y la siguiente habrá sólo 4 minutos entre lotes , después de 00:56una nueva serie comienza en 01:00, 01:07etc. (y los lotes no se ejecutará en 01:03, 01:10, 01:17etc.).


¿Qué hacer en su lugar?

Crea múltiples lotes

En lugar de un solo trabajo cron, cree varios lotes que combinen el resultado en la programación deseada.

Por ejemplo, para ejecutar un lote cada 40 minutos (00:00, 00:40, 01:20, 02:00, etc.) cree dos lotes, uno que se ejecute dos veces en las horas pares y el segundo que ejecute solo las horas impares:

# The following lines create a batch that runs every 40 minutes i.e.

# runs on   0:00, 0:40,        02:00, 02:40         04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command

# runs on               01:20,               03:20,       etc to 23:20
20 1/2 * * * /path/to/your/command

# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.

Ejecute sus lotes con menos frecuencia

En lugar de ejecutar su lote cada 7 minutos, que es un cronograma difícil de dividir en varios lotes, simplemente ejecútelo cada 10 minutos.

Inicie sus lotes con más frecuencia (pero evite que se ejecuten varios lotes simultáneamente)

Muchos horarios impares evolucionan porque los tiempos de ejecución de los lotes aumentan / fluctúan y luego los lotes se programan con un poco de margen de seguridad adicional para evitar que las ejecuciones posteriores del mismo lote se superpongan y se ejecuten simultáneamente.

En cambio, piense de manera diferente y cree un cronjob que fallará con gracia cuando una ejecución anterior aún no haya finalizado, pero que se ejecutará de otra manera. Vea estas preguntas y respuestas :

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job 

Eso comenzará casi inmediatamente una nueva ejecución una vez que se haya completado la ejecución anterior de / usr / local / bin / frequency_cron_job.

Comience sus lotes con más frecuencia (pero salga con gracia cuando las condiciones no sean las correctas)

Dado que la sintaxis cron es limitada, puede decidir colocar condiciones y lógica más complejas en el trabajo por lotes en sí (o en un script de envoltura alrededor del trabajo por lotes existente). Eso le permite utilizar las capacidades avanzadas de sus lenguajes de secuencias de comandos favoritos, comentar su código y evitará construcciones difíciles de leer en la entrada crontab.

En bash seven-minute-job, entonces se vería algo así como:

#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated

if [ ! -f /tmp/lastrun ] ; then
    touch /tmp/lastrun
fi

if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
     # The minimum interval of 7 minutes between successive batches hasn't passed yet.
    exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF

Que luego puede ejecutar de forma segura (intentar) cada minuto:

* * * * * /path/to/your/seven-minute-job

Un problema diferente pero similar sería programar un lote para que se ejecute el primer lunes de cada mes (o el segundo miércoles), etc. Simplemente programe el lote para que se ejecute todos los lunes y salga cuando la fecha no sea entre el 1 ° o el 7 ° y El día de la semana no es lunes.

#!/bin/bash
# first-monday-of-the-month-housekeeping-job

# exit if today is not a Monday (and prevent locale issues by using the day number) 
if [ $(date +%u) != 1 ] ; then
  exit 0
fi

# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
  exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#EOF

Que luego puede ejecutar de forma segura (intentar) todos los lunes:

0 0 * * 1 /path/to/your/first-monday-of-the-month-housekeeping-job

No uses cron

Si sus necesidades son complejas, puede considerar usar un producto más avanzado que esté diseñado para ejecutar programaciones complejas (distribuidas en varios servidores) y que admita desencadenantes, dependencias de trabajo, manejo de errores, reintentos y reintento de monitoreo, etc. La jerga de la industria sería "empresarial " programación de trabajo y / o" automatización de carga de trabajo ".

HBruijn
fuente
8

PHP específico

Si tienes algún trabajo cron como:

php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log

Y en caso de errores esperados, se los enviarán, pero no lo hacen, verifique esto.

PHP por defecto no envía errores a STDOUT. @ver https://bugs.php.net/bug.php?id=22839

Para solucionar esto, agregue cli`s php.ini o en su línea (o en el bash wrapper de su PHP) estos:

  • --define display_startup_errors = 1
  • --define display_errors = 'stderr'

La primera configuración le permitirá tener fatals como 'Memory oops' y la segunda para redirigirlos a STDERR. Solo después de que pueda dormir bien, todo se enviará al correo de su raíz en lugar de solo registrarse.

gaRex
fuente
2
Ese informe de error se cerró en 2007 con el estado del parche agregado a las ramas PHP 5.2+. ¿Estás seguro de que esto es necesario? Acabo de probar en PHP 5.4 y parece funcionar bien. (Sin embargo, todavía es necesario para PHP 4).
Xeoncross
@Xeoncross ver fecha de respuesta :)
gaRex
1
Sí, eso es lo que me confundió desde que respondiste en 2013 y el boleto fue en el '07.
Xeoncross
0

Agregando mi respuesta desde aquí para completar, y agregando otro recurso potencialmente útil:

El cronusuario tiene una diferente $PATHa la suya:

Un problema frecuente que los usuarios hacen con las crontabentradas es que se olvidan de que se cronejecuta de forma diferente environmenta como lo hacen como un usuario conectado. Por ejemplo, un usuario crea un programa o script en su $HOMEdirectorio e ingresa el siguiente comando para ejecutarlo:

$ ./certbot ... 

El comando se ejecuta perfectamente desde su línea de comando. El usuario luego agrega ese comando al suyo crontab, pero descubre que esto no funciona:

*/10 * * * * ./certbot ....

La razón de la falla en este caso es que ./es una ubicación diferente para el cronusuario que para el usuario que inició sesión. Es decir, el environmentes diferente! La RUTA es parte de environment, y generalmente es diferente para el cronusuario. Para complicar este problema, el environmentfor cronno es el mismo para todas las distribuciones * nix , y hay varias versiones decron

Una solución simple a este problema particular es darle al cronusuario una especificación de ruta completa en la crontabentrada:

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

¿Qué es el cronusuario environment?

En algunos casos, es posible que necesitemos conocer la environmentespecificación completa de cronnuestro sistema (o puede que solo tengamos curiosidad). ¿Qué es environmentpara el cronusuario y en qué se diferencia del nuestro? Además, es posible que necesitemos saber environmentpara otro cronusuario, rootpor ejemplo ... ¿qué está usando el rootusuario ? Una forma de aprender esto es pedirnos que nos digan: environmentcroncron

  1. Cree un script de shell en su directorio de inicio ( ~/) de la siguiente manera (o con el editor de su elección):
$ nano ~/envtst.sh
  1. Ingrese lo siguiente en el editor, después de ajustar para su sistema / usuario:
#!/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
  1. Guarde el archivo, salga del editor y configure los permisos del archivo como ejecutable.
$ chmod a+rx ~/envtst.sh
  1. Ejecute el script que acaba de crear y revise el resultado en /home/you/envtst.sh.out. Este resultado mostrará su entorno actual cuando haya $USERiniciado sesión como:
$ ./envtst.sh $$ cat /home/you/envtst.sh.out
  1. Abre tu crontabpara editar:
$ crontab -e -u root
  1. Ingrese la siguiente línea en la parte inferior de su crontab:
* * * * *  /home/you/envtst.sh >> /home/you/envtst.sh.err 2>&1

RESPUESTA: El archivo de salida /home/you/envtst.sh.outcontendrá una lista de environment"usuario cron cron". Una vez que sepa eso, ajuste su crontabentrada en consecuencia.

No puedo especificar el horario que necesito en mi crontabentrada:

La entrada de programación para, crontabpor supuesto, se define en man crontab, y debe leer esto. Sin embargo, leer man crontaby comprender el horario son dos cosas diferentes. Y la prueba y error en una especificación de programación puede volverse muy tediosa. Afortunadamente, hay un recurso que puede ayudar: el crontab guru. . Ingrese la especificación de su horario, y le explicará el horario en un lenguaje sencillo en inglés.

Finalmente, y en riesgo de ser redundante con una de las otras respuestas aquí, no se deje atrapar por pensar que está limitado a una sola crontabentrada porque tiene un trabajo que programar. Puede utilizar tantas crontabentradas como sea necesario para obtener la programación que necesita.

Seamus
fuente