1. Qué es cron
cron es un servicio del sistema, un demonio, que se despierta una vez por minuto, revisa unas tablas de tareas llamadas crontabs y ejecuta las que corresponden a ese minuto. Cada línea de un crontab dice cuándo y qué: una expresión de tiempo y un comando.
El nombre viene del griego chronos, tiempo. Existe desde los primeros Unix, y casi todas las distribuciones de Linux lo traen instalado y en marcha: Debian y Ubuntu usan una versión derivada del cron de Paul Vixie, y Fedora, RHEL y sus derivadas usan cronie, otra variante del mismo. Para lo que se ve en este tema se comportan igual; donde difieren, lo indicaremos.
$ systemctl is-active cron # en Fedora y RHEL, el servicio se llama crond
active
Cron es la forma más difundida, pero no la única, de programar tareas. Los temporizadores de systemd y el comando at, que veremos en el tema 35, cubren casos que cron resuelve mal. Pero las expresiones de cron aparecen en todas partes, desde los servidores de integración continua hasta los servicios en la nube, y vale la pena dominarlas.
2. El crontab de cada usuario
Cada usuario tiene su propio crontab, y sus tareas se ejecutan con sus permisos. No se edita directamente el archivo donde se guarda, sino con el comando crontab:
| Comando | Efecto |
|---|---|
crontab -e | Abre el crontab en un editor; al guardar, lo valida e instala. |
crontab -l | Muestra el crontab actual. Si no hay ninguno, falla con no crontab for usuario. |
crontab archivo | Reemplaza el crontab por el contenido de un archivo. |
crontab - | Lo reemplaza por lo que llega a la entrada estándar. |
crontab -r | Borra el crontab entero, sin preguntar. |
sudo crontab -u ana -l | Opera sobre el crontab de otro usuario; requiere ser root. |
$ crontab -l
no crontab for ana
$ crontab -e
no crontab for ana - using an empty one
crontab: installing new crontab
$ crontab -l
# m h dom mon dow command
30 2 * * * /home/ana/bin/respaldar -q
crontab -e usa el editor que indican las variables VISUAL o EDITOR; en Debian y Ubuntu, la primera vez pregunta cuál usar. Al guardar, comprueba la sintaxis de cada línea, y si encuentra un error no instala nada y ofrece volver a editar. Esa validación es la razón para no tocar a mano los archivos de /var/spool/cron/, donde cron guarda los crontabs: un error escrito allí pasa sin aviso, y la tarea simplemente no corre.
Las líneas que empiezan con # son comentarios, y las vacías se ignoran. Conviene usar los comentarios: dentro de un año, 15 4 * * 0 /usr/local/bin/x2 no le dirá nada a nadie.
En el teclado, -r queda junto a -e, y crontab -r borra todas las tareas sin confirmación ni posibilidad de deshacer. Antes de cualquier cambio importante, guarda una copia con crontab -l > ~/crontab.respaldo, que se restaura con crontab ~/crontab.respaldo. cronie acepta además crontab -ri, que pide confirmación antes de borrar.
3. Los cinco campos de tiempo
Una línea de crontab tiene cinco campos de tiempo, separados por espacios o tabulaciones, y después el comando, que ocupa el resto de la línea:
Cron compara cada minuto la hora actual con los cinco campos, y ejecuta el comando si coinciden todos. El asterisco significa «cualquier valor», de modo que 30 2 * * 1-5 se lee: «en el minuto 30, de la hora 2, cualquier día del mes, cualquier mes, si el día de la semana está entre el lunes y el viernes». Las horas van de 0 a 23, sin a.m. ni p.m.: las 2 de la tarde son 14.
Una ayuda para no confundir el orden es leerlo de lo más pequeño a lo más grande: minuto, hora, día, mes. El día de la semana, que no encaja en esa escala, va al final. Mucha gente copia sobre sus tareas un comentario como el que pone Debian en un crontab nuevo, # m h dom mon dow command, que recuerda el orden.
4. Valores, listas, rangos y pasos
Cada campo puede contener algo más que un número o un asterisco:
| Forma | Ejemplo | Significa |
|---|---|---|
| Asterisco | * | Cualquier valor del campo. |
| Valor | 5 | Solo ese valor. |
| Lista | 1,15 | Cualquiera de los valores, separados por comas y sin espacios. |
| Rango | 9-17 | Todos los valores entre los dos, incluidos. |
| Paso sobre todo el campo | */15 | Uno de cada 15 desde el primer valor: en minutos, 0, 15, 30 y 45. |
| Paso sobre un rango | 0-30/10 | 0, 10, 20 y 30. |
| Combinaciones | 0-10,30,50-59 | Una lista de valores y rangos. |
| Nombres | mon, jan | Las tres primeras letras, en inglés, para el mes y el día de la semana. |
Los pasos cuentan desde el comienzo del rango, no desde el momento en que se instaló la tarea, y empiezan de nuevo en cada hora, día o mes. Por eso */15 en minutos es regular, porque 15 divide a 60, pero */7 no lo es: produce 0, 7, 14… 49, 56, y luego vuelve a 0, solo cuatro minutos después. Del mismo modo, */2 en el día del mes da los días impares, y el 31 y el 1 quedan seguidos. Para un intervalo exacto que no divide la unidad, cron no es la herramienta adecuada.
Los nombres, como mon-fri, se leen mejor que los números, pero el cron de Debian no los admite en rangos ni en listas. Si el crontab debe funcionar en cualquier sistema, conviene usar números en esos casos.
5. Expresiones habituales
Con esas piezas se arman casi todos los horarios que se necesitan en la práctica:
| Expresión | Se ejecuta |
|---|---|
* * * * * | Cada minuto. |
*/5 * * * * | Cada 5 minutos. |
0 * * * * | Al comienzo de cada hora. |
15 */2 * * * | A las 0:15, 2:15, 4:15… cada dos horas. |
30 2 * * * | Todos los días a las 2:30. |
0 8,20 * * * | Todos los días a las 8:00 y a las 20:00. |
0 9-18 * * 1-5 | Cada hora en punto de 9 a 18, de lunes a viernes. |
0 12 * * 1,3,5 | Lunes, miércoles y viernes al mediodía. |
0 0 * * 0 | Los domingos a medianoche. |
0 8 1 * * | El día 1 de cada mes a las 8:00. |
0 3 1 */3 * | El 1 de enero, abril, julio y octubre a las 3:00. |
0 0 1 1 * | Una vez al año, el 1 de enero a medianoche. |
Un detalle que conviene fijar: para que algo ocurra a una hora determinada, el minuto debe tener un valor. * 2 * * * no significa «a las 2», sino «cada minuto entre las 2:00 y las 2:59»: sesenta ejecuciones.
Y otro, si muchas máquinas o muchas tareas usan la misma expresión: todos eligen 0 * * * * o 0 0 * * *, y a esa hora coinciden todas a la vez. Para tareas que pueden correr a cualquier minuto, elegir uno poco redondo, como 17 o 43, reparte la carga. Es lo que hace el propio /etc/crontab de Debian, que ejecuta las tareas horarias en el minuto 17.
6. Día del mes o día de la semana
Hay una regla de cron que contradice la lectura natural de una expresión. Los campos se combinan con «y», salvo un caso: si el día del mes y el día de la semana tienen los dos un valor distinto de *, la tarea se ejecuta cuando coincide cualquiera de los dos.
0 9 13 * 5 # NO es «los viernes 13»: es todos los días 13, y además todos los viernes
0 9 1 * 1 # el día 1 de cada mes, y además todos los lunes
Para expresar «el primer lunes del mes» o «los viernes 13», se programa la tarea con uno de los dos campos y se agrega una condición en el comando. El primer lunes de un mes es el único lunes entre los días 1 y 7; el último día del mes es aquel cuyo día siguiente es 1:
# El primer lunes de cada mes: días 1 a 7, y hoy es lunes (date +%u da 1)
0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /home/ana/bin/reunion-mensual
# Los viernes 13
0 9 13 * * [ "$(date +\%u)" = 5 ] && /home/ana/bin/supersticion
# El último día de cada mes: mañana es día 1
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /home/ana/bin/cierre-mensual
Las barras antes de cada % no son un descuido: en un crontab, el % tiene un significado especial, como se explica en la sección 8. La condición también puede ir dentro del script, como su primera comprobación, y es lo más claro cuando la regla es complicada.
7. Las cadenas especiales
En lugar de los cinco campos, una línea puede empezar con una cadena que abrevia los horarios más comunes:
| Cadena | Equivale a | Se ejecuta |
|---|---|---|
@reboot | — | Una vez, cuando arranca cron, es decir, al iniciar el sistema. |
@hourly | 0 * * * * | Al comienzo de cada hora. |
@daily, @midnight | 0 0 * * * | Todos los días a medianoche. |
@weekly | 0 0 * * 0 | Los domingos a medianoche. |
@monthly | 0 0 1 * * | El día 1 de cada mes a medianoche. |
@yearly, @annually | 0 0 1 1 * | El 1 de enero a medianoche. |
@reboot /home/ana/bin/montar-red
@weekly /home/ana/bin/limpiar-descargas
@reboot es la única que agrega algo que los cinco campos no pueden expresar. Hay que tener en cuenta que corre muy temprano en el arranque, cuando quizás la red o algún disco todavía no están disponibles: un script lanzado así debe estar preparado para esperar o reintentar. Para servicios que deben quedar en marcha, un servicio de systemd es más adecuado.
8. La línea del comando
El comando de una línea de crontab no se ejecuta en una terminal como la tuya. Cron se lo pasa a /bin/sh, desde el directorio personal del usuario y con un entorno mínimo. De eso se derivan varias reglas, algunas sorprendentes:
- La shell es
sh, no Bash. En Debian y Ubuntu,/bin/shesdash, que no entiende[[ ]], los arrays ni{1..5}. La solución más limpia es no escribir lógica en el crontab: poner todo en un script con su línea#!/usr/bin/env bash, y que el crontab solo lo llame. - El
%es especial. Cron convierte cada%sin escapar en un salto de línea, y todo lo que sigue al primero se entrega como entrada estándar del comando. Un inocentedate +%Fen el crontab se corta endate +. Hay que escribir\%. - Todo en una línea. No hay continuación con barra invertida al final de la línea. Otra razón para que la lógica viva en un script.
- El
PATHes mínimo, normalmente/usr/bin:/bin: los programas de/usr/local/bino de~/binno se encuentran por su nombre. Lo más seguro es usar rutas absolutas. - La salida se envía por correo. Lo que el comando escribe en la salida estándar o en la de errores, cron lo manda por correo al usuario. Si el sistema no tiene correo configurado, lo más común hoy, esa salida se pierde, y con ella los mensajes de error.
Un crontab puede definir variables, en líneas con la forma NOMBRE=valor, que valen para las tareas que siguen. Las más útiles son SHELL, PATH y MAILTO, la dirección a la que va la salida; con MAILTO="", no se envía nada:
SHELL=/bin/bash
PATH=/home/ana/bin:/usr/local/bin:/usr/bin:/bin
MAILTO=ana@example.com
30 2 * * * respaldar -q
*/10 * * * * flock -n /tmp/sincronizar.lock sincronizar
Ojo con un detalle: estas asignaciones no son de shell, y cron no expande nada en ellas. PATH=$HOME/bin:$PATH deja en PATH exactamente ese texto, con el signo de pesos, y no se encuentra ningún programa. El valor se escribe completo.
La última línea del ejemplo muestra otro cuidado: si una tarea que corre cada 10 minutos alguna vez tarda más de 10, cron lanza la siguiente igual, y quedan dos ejecuciones simultáneas. Envolverla con flock -n, como vimos en el tema 27, hace que la segunda termine enseguida si la primera sigue en marcha. El entorno de cron, la forma de capturar la salida en un archivo de registro y cómo averiguar por qué una tarea no hizo lo que debía son el tema del tema 34.
Cron usa la hora local del sistema. En las zonas con horario de verano, el día del cambio una hora no existe o se repite, y una tarea programada a las 2:30 puede no ejecutarse o adelantarse, según la implementación. Para tareas importantes, conviene evitar el intervalo entre la 1 y las 3 de la madrugada, o usar en el servidor la hora UTC, que no tiene cambios. cronie permite además fijar la zona de cada crontab con la variable CRON_TZ.
9. Los crontabs del sistema
Además de los crontabs de usuario, hay crontabs del sistema, que administra root y que tienen un campo más: después de los cinco de tiempo, el usuario con el que se ejecuta el comando.
| Ubicación | Contenido |
|---|---|
/etc/crontab | El crontab principal del sistema, con el campo de usuario. |
/etc/cron.d/ | Archivos con el mismo formato, uno por aplicación o tarea. Es donde los paquetes y las herramientas de configuración instalan las suyas. |
/etc/cron.hourly/, daily/, weekly/, monthly/ | Scripts ejecutables, sin expresión de tiempo: se ejecutan todos, uno tras otro, con la frecuencia que indica el directorio. |
# Respaldo nocturno de la base de datos
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
30 2 * * * backup /usr/local/bin/respaldar -q
Para una tarea del sistema, un archivo propio en /etc/cron.d/ tiene ventajas sobre el crontab de root: se instala y se borra como cualquier archivo, se puede guardar en un repositorio y, como indica el usuario, permite ejecutar la tarea con una cuenta sin privilegios, como backup en el ejemplo. Pero tiene reglas estrictas, y si no se cumplen, cron ignora el archivo en silencio: debe pertenecer a root, no debe poder modificarlo nadie más, y la última línea debe terminar con un salto de línea. En Debian y Ubuntu, además, el nombre solo puede tener letras, dígitos, guiones y guiones bajos: respaldo.cron se ignora.
Los directorios cron.daily y sus hermanos los recorre el comando run-parts, con las mismas reglas de nombres, de modo que un script llamado limpiar.sh tampoco se ejecuta en Debian. En muchos sistemas los lanza anacron, una herramienta pensada para equipos que no están siempre encendidos: si a la hora prevista la máquina estaba apagada, anacron ejecuta la tarea diaria cuando vuelve a arrancar. Cron, en cambio, nunca recupera las ejecuciones perdidas: si el portátil estaba cerrado a las 2:30, el respaldo de esa noche no se hizo.
Por último, el administrador puede decidir quién usa cron, con los archivos /etc/cron.allow y /etc/cron.deny: si existe el primero, solo los usuarios que figuran en él pueden tener un crontab; si no, pueden todos salvo los del segundo.
10. Probar una tarea nueva
Una tarea de cron que falla no avisa a nadie: simplemente no ocurre, y uno se entera semanas después, cuando necesita el respaldo. Antes de dar una tarea por terminada:
- Ejecutar el comando a mano, exactamente como figura en el crontab, con rutas absolutas y los
%sin la barra. Si falla aquí, fallará en cron. a mano - Programarla para dentro de dos minutos, con un horario de prueba como
47 10 * * *, o cada minuto, y comprobar que hizo lo que debía: que el archivo apareció, que el registro tiene la línea nueva. en cron - Mirar el registro de cron, que anota cada ejecución con el usuario y el comando. sistema
- Poner el horario definitivo, y revisar el resultado tras la primera ejecución real. definitivo
$ (crontab -l; echo '* * * * * date >> /tmp/prueba-cron.txt') | crontab -
# … un par de minutos después:
$ cat /tmp/prueba-cron.txt
jue 15 oct 2026 10:47:01 -03
jue 15 oct 2026 10:48:01 -03
$ journalctl -u cron --since '10 min ago' # crond en Fedora y RHEL
oct 15 10:47:01 servidor CRON[48211]: (ana) CMD (date >> /tmp/prueba-cron.txt)
oct 15 10:48:01 servidor CRON[48263]: (ana) CMD (date >> /tmp/prueba-cron.txt)
$ crontab -l | grep -v prueba-cron | crontab - # quitar la línea de prueba
Las ejecuciones empiezan en el segundo 1 de cada minuto, y el registro confirma que cron lanzó el comando. Lo que no confirma es que el comando haya funcionado: para eso hay que mirar su resultado o su propio registro. En los sistemas sin journald, las mismas líneas están en /var/log/syslog o en /var/log/cron. La primera línea del ejemplo es, además, la forma de agregar una tarea sin abrir un editor, la que usa el script de la sección siguiente.
11. Un script completo
Editar el crontab a mano está bien para una tarea; pero cuando un script de instalación tiene que dejar programadas las suyas, abrir un editor no es una opción, y agregar la línea con echo la duplica en cada ejecución, el problema que vimos en el tema 27. Este script agrega, cambia y quita tareas del crontab del usuario, identificándolas por un nombre. Es idempotente: ejecutarlo dos veces con los mismos datos no cambia nada.
#!/usr/bin/env bash
#
# cron-tarea — agrega, cambia y quita tareas del crontab del usuario,
# identificadas por un nombre, sin duplicarlas.
#
# Uso: cron-tarea poner NOMBRE 'MIN HORA DÍA MES DÍASEM' COMANDO
# cron-tarea quitar NOMBRE
# cron-tarea listar
#
set -euo pipefail
prog="${0##*/}"
marca='# cron-tarea:'
respaldo="$HOME/.crontab.anterior"
uso() {
echo "Uso: $prog poner NOMBRE 'MIN HORA DÍA MES DÍASEM' COMANDO" >&2
echo " $prog quitar NOMBRE" >&2
echo " $prog listar" >&2
exit 2
}
error() { echo "$prog: $*" >&2; exit 1; }
horario_valido() {
local campo='[0-9A-Za-z*,/-]+'
local cinco="^$campo +$campo +$campo +$campo +$campo\$"
local especial='^@(reboot|hourly|daily|midnight|weekly|monthly|yearly|annually)$'
[[ "$1" =~ $cinco || "$1" =~ $especial ]]
}
leer_crontab() { # el crontab actual; si no hay, nada
crontab -l 2>/dev/null || true
}
editar() { # aplica el programa awk $1 al crontab actual
printf '%s' "${actual:+$actual$'\n'}" | MARCA="$marca$nombre" LINEA="${linea:-}" awk "$1"
}
instalar() { # reemplaza el crontab por $1, guardando el anterior
printf '%s\n' "$actual" > "$respaldo"
printf '%s\n' "$1" | crontab -
}
(( $# >= 1 )) || uso
accion="$1"; shift
case "$accion" in
poner)
(( $# == 3 )) || uso
nombre="$1" horario="$2" comando="$3"
[[ "$nombre" =~ ^[a-z0-9][a-z0-9-]*$ ]] || error "nombre no válido: $nombre"
horario_valido "$horario" || error "horario no válido: $horario"
[[ "$comando" != *$'\n'* ]] || error "el comando debe ocupar una sola línea"
comando="${comando//%/'\%'}" # en un crontab, % significa salto de línea
linea="$horario $comando"
actual=$(leer_crontab)
nuevo=$(editar '
cambiar { cambiar = 0; print ENVIRON["LINEA"]; next }
$0 == ENVIRON["MARCA"] { cambiar = 1; hay = 1 }
{ print }
END { if (!hay) { print ENVIRON["MARCA"]; print ENVIRON["LINEA"] } }')
if [[ "$nuevo" == "$actual" ]]; then
echo "La tarea $nombre ya estaba programada así; no hay cambios." >&2
else
instalar "$nuevo"
echo "Tarea $nombre programada: $linea" >&2
fi
;;
quitar)
(( $# == 1 )) || uso
nombre="$1"
actual=$(leer_crontab)
nuevo=$(editar '
saltar { saltar = 0; next }
$0 == ENVIRON["MARCA"] { saltar = 1; next }
{ print }')
if [[ "$nuevo" == "$actual" ]]; then
echo "No había ninguna tarea llamada $nombre; no hay cambios." >&2
else
instalar "$nuevo"
echo "Tarea $nombre quitada." >&2
fi
;;
listar)
leer_crontab | awk -v m="$marca" '
index($0, m) == 1 { nombre = substr($0, length(m) + 1); getline; printf "%-10s %s\n", nombre, $0 }'
;;
*) uso ;;
esac
$ crontab -l
# Mis tareas
MAILTO=ana@example.com
$ cron-tarea poner respaldo '30 2 * * *' '/home/ana/bin/respaldar -q'
Tarea respaldo programada: 30 2 * * * /home/ana/bin/respaldar -q
$ cron-tarea poner informe '0 8 * * 1-5' '/home/ana/bin/informe > /tmp/informe-$(date +%F).txt'
Tarea informe programada: 0 8 * * 1-5 /home/ana/bin/informe > /tmp/informe-$(date +\%F).txt
$ cron-tarea poner respaldo '30 2 * * *' '/home/ana/bin/respaldar -q'
La tarea respaldo ya estaba programada así; no hay cambios.
$ cron-tarea poner respaldo '0 3 * * *' '/home/ana/bin/respaldar -q'
Tarea respaldo programada: 0 3 * * * /home/ana/bin/respaldar -q
$ crontab -l
# Mis tareas
MAILTO=ana@example.com
# cron-tarea:respaldo
0 3 * * * /home/ana/bin/respaldar -q
# cron-tarea:informe
0 8 * * 1-5 /home/ana/bin/informe > /tmp/informe-$(date +\%F).txt
$ cron-tarea listar
respaldo 0 3 * * * /home/ana/bin/respaldar -q
informe 0 8 * * 1-5 /home/ana/bin/informe > /tmp/informe-$(date +\%F).txt
$ cron-tarea poner limpiar '5 * * *' 'rm -f /tmp/app/*'
cron-tarea: horario no válido: 5 * * *
$ cron-tarea quitar informe
Tarea informe quitada.
$ cron-tarea quitar informe
No había ninguna tarea llamada informe; no hay cambios.
- Cada tarea lleva una marca: un comentario
# cron-tarea:nombreen la línea anterior. Para cron es un comentario más; para el script, la forma de encontrar su línea sin confundirla con las que el usuario escribió a mano, que quedan intactas, comoMAILTOen el ejemplo. - Leer, transformar, instalar: el script nunca edita el crontab en su lugar. Lee el actual con
crontab -l, calcula el nuevo conawky lo instala entero concrontab -, que además valida la sintaxis: si la rechaza, el modo estricto detiene el script con el mensaje decrontab, y el crontab anterior sigue vigente. - Cambiar es reemplazar en el lugar: si la marca ya existe,
awkreemplaza la línea siguiente por la nueva; si no, agrega las dos al final. Así, cambiar el horario derespaldono lo mueve ni lo duplica. - Es idempotente: antes de instalar, compara el crontab nuevo con el actual, y si son iguales no hace nada. Lo mismo al quitar una tarea que no existe: no es un error, porque el resultado deseado, que la tarea no esté, ya se cumple.
- Los datos llegan a
awkporENVIRON, como vimos en el tema 29. Con-v,awkinterpretaría las barras invertidas, y el\%llegaría como%, que es justamente lo que había que evitar.editareinstalarleen las variablesactual,nombreylineadel script, lo que en un script tan corto deja las llamadas más simples. - Protege la línea del comando: escapa cada
%con la expansión del tema 6, y rechaza los comandos con saltos de línea, que en un crontab no tienen forma de escribirse. El reemplazo'\%'va entre comillas simples para que se lea tal cual: una barra y un porcentaje. - La validación del horario es de forma, con las expresiones regulares del tema 28: comprueba que haya cinco campos con caracteres posibles, o una cadena especial, pero no que
75sea un minuto imposible. De eso se encargacrontabal instalar. - Guarda el crontab anterior en
~/.crontab.anteriorantes de cada cambio. Si algo sale mal,crontab ~/.crontab.anteriorlo restaura.
El script pierde un único caso: si el usuario borra a mano la marca y deja la línea, el script ya no la reconoce, y un nuevo poner la duplicaría. Es el compromiso de cualquier herramienta que comparte un archivo con las personas.
12. Errores frecuentes
| Escribiste | Qué pasa | Corrección |
|---|---|---|
crontab -r en lugar de -e | Se borran todas las tareas, sin preguntar. | Guardar antes una copia con crontab -l > archivo. |
* 2 * * * para «a las 2» | Se ejecuta cada minuto entre las 2:00 y las 2:59. | 0 2 * * * |
date +%F en la línea | El comando se corta en el %; el resto va a su entrada. | date +\%F, o llevarlo a un script. |
0 9 13 * 5 para «los viernes 13» | Se ejecuta todos los días 13 y todos los viernes. | 0 9 13 * * y comprobar el día en el comando. |
[[ ]], arrays o {1..5} en la línea | /bin/sh puede ser dash, que no los entiende. | Un script con #!/usr/bin/env bash, o SHELL=/bin/bash. |
Un programa sin ruta, como respaldar | Con el PATH de cron no se encuentra. | Ruta absoluta, o un PATH completo al comienzo del crontab. |
PATH=$HOME/bin:$PATH en el crontab | Cron no expande variables: queda el texto literal. | Escribir el valor completo. |
Una tarea */5 que a veces tarda más de 5 minutos | Se acumulan ejecuciones simultáneas. | flock -n archivo comando |
/etc/cron.d/respaldo.cron | En Debian y Ubuntu, un nombre con punto se ignora. | /etc/cron.d/respaldo |
| La última línea sin salto de línea final | Esa línea se ignora. | Terminar el archivo con un salto de línea. |
Editar los archivos de /var/spool/cron/ | Sin validación: un error pasa en silencio. | crontab -e o crontab archivo. |
13. Resumen
- cron es un servicio que cada minuto revisa los crontabs y ejecuta las tareas que corresponden.
- Cada usuario tiene su crontab, que se edita con
crontab -e, se muestra concrontab -ly se reemplaza concrontab archivoocrontab -;crontab -rlo borra sin preguntar. - Una línea tiene cinco campos, minuto, hora, día del mes, mes y día de la semana, seguidos del comando.
- Cada campo admite
*, valores, listas con comas, rangos con guion y pasos con barra; los pasos empiezan de nuevo en cada unidad. - Si el día del mes y el día de la semana tienen valores, basta con que coincida uno; las reglas como «el primer lunes» se completan con una condición en el comando.
- Las cadenas
@reboot,@hourly,@daily,@weekly,@monthlyy@yearlyabrevian los horarios comunes. - El comando lo ejecuta
/bin/shcon unPATHmínimo; el%debe escaparse, todo va en una línea, y la salida va por correo o se pierde. Lo mejor es que el crontab solo llame a un script. - Las variables del crontab, como
PATH,SHELLyMAILTO, no se expanden. /etc/crontaby/etc/cron.d/agregan el campo de usuario;cron.dailyy sus hermanos ejecutan scripts con una frecuencia fija. Cron no recupera las ejecuciones perdidas; anacron sí.- Una tarea nueva se prueba a mano, luego en cron con un horario cercano, y se confirma en el registro de cron y en su resultado.
14. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Por qué no conviene editar a mano los archivos de /var/spool/cron/?
Porque así se saltea la validación que hace el comando crontab: una línea mal escrita no se detecta, y la tarea simplemente no se ejecuta. Además, cron podría no advertir el cambio.
2. ¿Cuándo se ejecuta 45 23 * * 5?
Todos los viernes a las 23:45.
3. ¿Cómo se escribe «cada 15 minutos, de 8 a 18, de lunes a viernes»?
*/15 8-18 * * 1-5. Se ejecuta en los minutos 0, 15, 30 y 45 de cada hora entre las 8 y las 18, incluida la hora 18, de modo que la última ejecución del día es a las 18:45.
4. ¿Qué tiene de raro */7 en el campo de los minutos?
Que el paso empieza de nuevo cada hora: produce 0, 7, 14… 56, y luego 0 otra vez, solo cuatro minutos después. Como 7 no divide a 60, los intervalos no son todos iguales.
5. ¿Cuándo se ejecuta 0 9 1 * 1?
A las 9 del día 1 de cada mes, y además a las 9 de todos los lunes: como el día del mes y el día de la semana tienen valores, basta con que coincida uno de los dos.
6. ¿Qué diferencia hay entre * 3 * * * y 0 3 * * *?
La primera se ejecuta cada minuto entre las 3:00 y las 3:59, sesenta veces; la segunda, una sola vez, a las 3:00.
7. ¿Por qué falla 0 0 * * * tar czf /respaldos/casa-$(date +%F).tgz /home/ana en un crontab?
Porque cron convierte el % en un salto de línea, y el comando se corta en date +. Hay que escribir \%F. Además, convendría usar la ruta absoluta de tar o llevar el comando a un script.
8. ¿Qué ocurre con una línea PATH=$HOME/bin:/usr/bin:/bin en un crontab?
Cron no expande variables en sus asignaciones, de modo que el PATH contiene literalmente $HOME/bin, que no es ningún directorio. Hay que escribir la ruta completa, como /home/ana/bin.
9. ¿Qué diferencia hay entre una línea de /etc/cron.d/ y una del crontab de un usuario?
La de /etc/cron.d/ tiene un campo más, después de los cinco de tiempo: el usuario con el que se ejecuta el comando. En el crontab de un usuario, las tareas se ejecutan siempre como ese usuario.
10. ¿Por qué cron-tarea pasa el comando a awk con ENVIRON y no con -v?
Porque -v interpreta las secuencias con barra invertida, y el \% que el script acaba de escribir se convertiría otra vez en %. ENVIRON entrega el valor exacto.
Para practicar
- Escribe la expresión de cron para cada caso: todos los días a las 6:45; cada 10 minutos; los sábados y domingos a las 10; el día 15 de cada mes a mediodía; cada dos horas, a la hora en punto, solo los días hábiles.
- Guarda una copia de tu crontab, agrega con
crontab -euna tarea que escriba la fecha en un archivo cada minuto, comprueba el archivo y el registro de cron, y luego restaura la copia. - Agrega una tarea que use
date +%H:%Msin escapar los%, y observa qué queda en el archivo de salida. Luego corrígela. - Programa una tarea para «el último viernes de cada mes» usando una condición en el comando.
- Usa
cron-tareapara programar, cambiar y quitar una tarea, y comprueba concrontab -lque las líneas que escribiste a mano no se modificaron. - Agrega a
cron-tareauna acciónpausar NOMBRE, que comente la línea de la tarea sin quitarla, y otrareanudar NOMBRE, que la vuelva a activar.