Curso de Bash desde cero / Capítulo 11
Cron
Abrir el explorador de archivos
A veces viene bien saltar de la terminal a la ventana de archivos, en la carpeta en la que estás. El punto significa «aquí».
| Sistema | Comando |
|---|---|
| Linux | xdg-open . |
| macOS | open . |
| Windows (desde WSL) | explorer.exe . |
Crontab
Cron es un demonio (daemon) del sistema que permite ejecutar tareas programadas automáticamente. Siempre está corriendo en segundo plano. De esta forma, una vez configurado, el sistema ejecuta las tareas sin que el usuario tenga que intervenir.
Nota
Cron usa unas tablas llamadas crontab. Hay una por usuario (la tuya, la que editas con
crontab -e) y otra general del sistema, en/etc/crontab, que solo puede tocar el administrador.
| Comando | Qué hace |
|---|---|
crontab -e |
Edita tu tabla de tareas |
crontab -l |
Lista tus tareas programadas |
crontab -r |
Borra tu tabla entera |
Precaución
Cuidado con
crontab -r: borra todas tus tareas de golpe y sin preguntar. Y está peligrosamente cerca decrontab -een el teclado.Antes de tocar nada, guarda una copia:
crontab -l > ~/copia-crontab.txt
Sintaxis crontab
Cada línea de crontab representa una tarea programada.
┌───────── minuto (0-59)
│ ┌─────── hora (0-23)
│ │ ┌───── día del mes (1-31)
│ │ │ ┌─── mes (1-12)
│ │ │ │ ┌─ día de la semana (0-7, donde 0 y 7 son domingo)
│ │ │ │ │
- comando_a_ejecutar
Cada * representa estas unidades de tiempo (de izquierda a derecha):
minuto (0-59)
hora (0-23)
día del mes (1-31)
mes (1-12)
día de la semana (0-7, donde 0 y 7 son domingo)
Consejo
Ejecuta primero de manera manual el comando para comprobar que funciona y que tienes los permisos adecuados.
Precaución
Si el comando a ejecutar es un script, utiliza su ruta absoluta.Ejemplos de sintaxis
| Línea | Cuándo se ejecuta |
|---|---|
30 2 * * * |
Todos los días a las 2:30 |
*/5 * * * * |
Cada 5 minutos |
0 9 * * 1 |
Todos los lunes a las 9:00 |
0 0 1 * * |
El día 1 de cada mes, a medianoche |
0 8 * * 1-5 |
De lunes a viernes a las 8:00 |
Comodines
| Símbolo | Significa | Ejemplo |
|---|---|---|
* |
Cualquier valor | * * * * * cada minuto |
, |
Lista de valores | 0 8,12 * * * a las 8 y a las 12 |
- |
Rango | 0 9-17 * * * cada hora de 9 a 17 |
*/n |
Cada n unidades | */10 * * * * cada 10 minutos |
Consejo
Para no equivocarte con la sintaxis, escribe la línea en crontab.guru: te la traduce a lenguaje normal mientras la escribes.
Antes de programar nada
Cron es una fuente inagotable de «pues a mí me funcionaba». Estas tres costumbres evitan casi todos los problemas:
Prueba el comando a mano primero. Si no funciona en tu terminal, tampoco va a funcionar en cron.
Usa rutas absolutas siempre, tanto para el script como para los archivos que toque. Cron no arranca en el directorio que tú crees.
Guarda la salida en un archivo mientras depuras, o no verás ningún error:
*/5 * * * * /home/nica/mi_script.sh >> /home/nica/cron.log 2>&1
Aviso
Cron ejecuta las tareas con un entorno casi vacío: un
PATHmínimo y sin tus variables ni tus alias del.bashrc. Por eso un script que va perfecto en tu terminal puede fallar en cron diciendo que no encuentra un comando.La solución es usar rutas absolutas también para los comandos, o definir el
PATHal principio del crontab:PATH=/usr/local/bin:/usr/bin:/bin
Ejercicios
Crea un script que muestre la fecha y hora actual en un archivo. Programa su ejecución cada minuto con una cron.
Crea un script que muestre “Hola desde cron” en un archivo. Configura cron para ejecutarlo cada 5 minutos.
Escribe un script de backup que comprima una carpeta en un archivo con fecha. Programa su ejecución cada día a las 2:00 AM.
Haz un script que borre archivos .log de una carpeta temporal. Programa su ejecución todos los domingos a la medianoche.
Programa un script que escriba la hora actual, ejecutándose cada hora de 9 a 17 (horario laboral).
Programa un script que muestre “Hoy toca practicar” en un archivo de log solo los lunes, miércoles y viernes a las 8:00 AM.
Modifica uno de los scripts para que su salida y errores se guarden en cron.log.
Programa un script que muestre “Sistema OK” y lo ejecute cada 10 minutos.
Crea un script que genere un archivo con la fecha actual. Prográmalo para ejecutarse el primer día de cada mes a medianoche.
Configura un script que escriba “Probando cron” en un archivo. Después, buscar información para revisar los logs del sistema y confirmar su ejecución.
Posibles correcciones
(ten en cuenta que pueden variar dependiendo de tu sistema operativo y directorios existentes)
- Crea un script que muestre la fecha y hora actual en un archivo. Programa su ejecución cada minuto con una cron.
#!/bin/bash
# Nombre: fecha_hora.sh
# Descripción: Guarda la fecha y hora actual en un archivo
# Definir el archivo de salida
archivo="$HOME/fecha_hora.log"
# Escribir la fecha y hora en el archivo
echo "Fecha y hora: $(date '+%d/%m/%Y %H:%M:%S')" >> "$archivo"Pasos para configurar:
# 1. Crear el script
nano ~/fecha_hora.sh
# 2. Dar permisos de ejecución
chmod +x ~/fecha_hora.sh
# 3. Probar el script
./fecha_hora.sh
cat ./fecha_hora.log
# 4. Editar crontab
crontab -e
# 5. Añadir esta línea al crontab:
* * * * * $HOME/fecha_hora.sh
# 6. Verificar que se añadió correctamente
crontab -l
# 7. Esperar 1-2 minutos y verificar el archivo
tail -f ~/fecha_hora.logExplicación del cron:
- comando
│ │ │ │ │
│ │ │ │ └─── Día de la semana (0-7, donde 0 y 7 = domingo)
│ │ │ └───── Mes (1-12)
│ │ └─────── Día del mes (1-31)
│ └───────── Hora (0-23)
└─────────── Minuto (0-59)
- = cada minuto/hora/día/mes/día de semana
- Crea un script que muestre “Hola desde cron” en un archivo. Configura cron para ejecutarlo cada 5 minutos.
#!/bin/bash
# Nombre: hola_cron.sh
# Descripción: Escribe un mensaje en un archivo cada 5 minutos
# Archivo de salida
archivo="$HOME/hola_cron.log"
# Escribir mensaje con fecha
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Hola desde cron" >> "$archivo"
Configurar crontab:
# 1. Crear y preparar el script
nano ~/hola_cron.sh
chmod +x ~/hola_cron.sh
# 2. Editar crontab
crontab -e
# 3. Añadir esta línea (ejecutar cada 5 minutos):
*/5 * * * * $HOME/hola_cron.sh
# 4. Verificar
crontab -l
# 5. Monitorear el archivo
tail -f ~/hola_cron.logExplicación
/5 * * * = Cada 5 minutos
/10 * * * = Cada 10 minutos
/15 * * * = Cada 15 minutos
/30 * * * = Cada 30 minutos
- Escribe un script de backup que comprima una carpeta en un archivo con fecha. Programa su ejecución cada día a las 2:00 AM.
#!/bin/bash
# Nombre: backup_diario.sh
# Descripción: Realiza backup comprimido de una carpeta
# Configuración
carpeta_origen="$HOME/documentos"
carpeta_destino="$HOME/backups"
fecha=$(date '+%Y%m%d_%H%M%S')
nombre_backup="backup_${fecha}.tar.gz"
# Crear carpeta de destino si no existe
mkdir -p "$carpeta_destino"
# Archivo donde se registra lo que pasa
log_file="$HOME/backups/backup.log"
# Realizar backup
tar -czf "$carpeta_destino/$nombre_backup" -C "$HOME" "documentos" 2>/dev/null
# OJO: $? hay que comprobarlo AQUI, en la linea siguiente al comando.
# Si entre medias metes cualquier otra cosa (aunque sea una asignacion),
# $? pasa a ser el resultado de ESA otra cosa y no el del tar.
if [ $? -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup exitoso: $nombre_backup" >> "$log_file"
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Error en backup" >> "$log_file"
fi
# Opcional: Eliminar backups antiguos (más de 7 días)
find "$carpeta_destino" -name "backup_*.tar.gz" -mtime +7 -deleteConfigurar crontab:
# 1. Crear el script
nano ~/backup_diario.sh
chmod +x ~/backup_diario.sh
# 2. Crear carpetas necesarias
mkdir -p ~/documentos ~/backups
# 3. Probar el script manualmente
~/backup_diario.sh
ls -lh ~/backups/
# 4. Editar crontab
crontab -e5. Añadir para ejecutar a las 2:00 AM diariamente:
0 2 * * * $HOME/backup_diario.sh
# 6. Verificar
crontab -lExplicación del cron:
0 2 * * * = A las 2:00 AM todos los días
30 3 * * * = A las 3:30 AM todos los días
0 0 * * * = A medianoche (00:00) todos los días
- Haz un script que borre archivos .log de una carpeta temporal. Programa su ejecución todos los domingos a la medianoche.
#!/bin/bash
# Nombre: limpiar_logs.sh
# Descripción: Elimina archivos .log de carpeta temporal
# Carpeta a limpiar
carpeta_temporal="$HOME/temp_logs"
# Archivo de registro
log_limpieza="$HOME/limpieza.log"
# Crear carpeta si no existe
mkdir -p "$carpeta_temporal"
# Contar archivos antes de eliminar
cantidad_antes=$(find "$carpeta_temporal" -name "*.log" -type f | wc -l)
# Eliminar archivos .log
find "$carpeta_temporal" -name "*.log" -type f -delete
# Contar archivos después
cantidad_despues=$(find "$carpeta_temporal" -name "*.log" -type
f | wc -l)
eliminados=$((cantidad_antes - cantidad_despues))
# Registrar la acción
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Archivos .log eliminados: $eliminados" >> "$log_limpieza"
Configurar crontab:
# 1. Crear el script
nano ~/limpiar_logs.sh
chmod +x ~/limpiar_logs.sh
# 2. Crear carpeta temporal y algunos archivos de prueba
mkdir -p ~/temp_logs
touch ~/temp_logs/test{1..5}.log
# 3. Probar el script
~/limpiar_logs.sh
cat ~/limpieza.log
# 4. Editar crontab
crontab -e
# 5. Añadir para ejecutar domingos a medianoche:0 0 * * 0 $HOME/limpiar_logs.sh
# 6. Verificar
crontab -lExplicación días de la semana:
0 0 * * 0 = Domingo a medianoche
0 0 * * 1 = Lunes a medianoche
0 0 * * 6 = Sábado a medianoche
0 0 * * 1-5 = lunes a viernes a medianoche
0 0 * * 0,6 = Fines de semana a medianoche
Días: 0 o 7 = Domingo, 1 = Lunes, 2 = Martes, …, 6 = Sábado
- Programa un script que escriba la hora actual, ejecutándose cada hora de 9 a 17 (horario laboral).
#!/bin/bash
# Nombre: horario_laboral.sh
# Descripción: Registra la hora durante el horario laboral
# Archivo de salida
archivo="$HOME/horario_laboral.log"
# Escribir hora actual
echo "Hora registrada: $(date '+%H:%M:%S - %d/%m/%Y')" >> "$archivo"
Configurar crontab:
# 1. Crear el script
nano ~/horario_laboral.sh
chmod +x ~/horario_laboral.sh
# 2. Probar
~/horario_laboral.sh
cat ~/horario_laboral.log
# 3. Editar crontab
crontab -e
# 4. Añadir para ejecutar cada hora de 9 AM a 5 PM:0 9-17 * * * $HOME/horario_laboral.sh
# El rango 9-17 SI incluye las 17:00, así que son 9 ejecuciones:
# 9, 10, 11, 12, 13, 14, 15, 16 y 17.
# Si quisieras llegar hasta las 18:00, tendrías que poner 9-18.
# 5. Verificar
crontab -lExplicación de rangos de hora:
0 9-17 * * * = Cada hora de 9:00 a 17:00
0 9-17 * * 1-5 = Cada hora de 9 a 17, solo lunes a viernes
30 9-17 * * * = A los 30 minutos de cada hora (9:30, 10:30, etc.)
0 8-18/2 * * * = Cada 2 horas de 8:00 a 18:00 (8, 10, 12, 14, 16, 18)
0 9,12,15,17 * * * = A las 9, 12, 15 y 17 horas
- Programa un script que muestre “Hoy toca practicar” en un archivo de log solo los lunes, miércoles y viernes a las 8:00 AM.
#!/bin/bash
# Nombre: practicar.sh
# Descripción: Recordatorio para practicar lunes, miércoles y viernes
# Archivo de log
archivo="$HOME/recordatorios.log"
# Obtener el día de la semana
dia_semana=$(date '+%A')
# Escribir mensaje
echo "[$(date '+%Y-%m-%d %H:%M:%S')] - $dia_semana - Hoy toca practicar" >> "$archivo"
Configurar crontab:
# 1. Crear el script
nano ~/practicar.sh
chmod +x ~/practicar.sh
# 2. Probar
~/practicar.sh
cat ~/recordatorios.log
# 3. Editar crontab
crontab -e
# 4. Añadir para lunes (1), miércoles (3) y viernes (5) a las 8:00
AM:0 8 * * 1,3,5 $HOME/practicar.sh
# 5. Verificar
crontab -lExplicación de múltiples das:
0 8 * * 1,3,5 = Lunes, miércoles y viernes a las 8:00 AM
0 8 * * 1-5 = Lunes a viernes (toda la semana laboral) a las 8:00 AM
0 8 * * 0,6 = Sábado y domingo a las 8:00 AM
0 8 * * 2,4 = Martes y jueves a las 8:00 AM
30 14 * * 1,3,5 = Lunes, miércoles y viernes a las 14:30
- Modifica uno de los scripts para que su salida y errores se guarden en cron.log.
#!/bin/bash
# Nombre: fecha_hora_logs.sh
# Descripción: Guarda fecha/hora con manejo de salida y errores
archivo="$HOME/fecha_hora_output.log"
# Simulando algunas operaciones que podrían generar salida y errores
echo "=== Inicio de ejecución ==="
echo "Fecha y hora: $(date '+%d/%m/%Y %H:%M:%S')" >> "$archivo"
# Verificar si el archivo se creó correctamente
if [ $? -eq 0 ]; then
echo "Registro exitoso"
else
echo "Error al escribir en el archivo" >&2
fiConfigurar crontab con redirección:
# 1. Crear el script
nano ~/fecha_hora_logs.sh
chmod +x ~/fecha_hora_logs.sh
# 2. Editar crontab
crontab -e
# 3. OPCIÓN 1: Redirigir salida estándar y errores al mismo archivo
* * * * * $HOME/fecha_hora_logs.sh >> $HOME/cron.log 2>&1
# 4. OPCIÓN 2: Redirigir a archivos separados
* * * * * $HOME/fecha_hora_logs.sh >> $HOME/cron_output.log
2>> $HOME/cron_error.log
# 5. OPCIÓN 3: Solo errores a archivo, salida descartada
* * * * * $HOME/fecha_hora_logs.sh > /dev/null 2>> $HOME/cron.log
# 6. Verificar
crontab -l
# 7. Ver los logs
tail -f ~/cron.logExplicación de redirecciones:
comando >> archivo.log 2>&1
>> = Añadir salida estándar al archivo
2>&1 = Redirigir errores (2) a donde va salida estándar (1)
comando > salida.log 2> error.log
> = Sobrescribir salida estándar
2> = Sobrescribir errores
comando &>> archivo.log
# &>> = Añadir tanto salida como errores (bash 4+)
comando > /dev/null 2>&1
# Descartar toda salida y errores- Programa un script que muestre “Sistema OK” y lo ejecute cada 10 minutos.
#!/bin/bash
# Nombre: sistema_ok.sh
# Descripción: Monitoreo simple del sistema
# Archivo de log
log_file="$HOME/sistema_monitor.log"
# Obtener información del sistema
carga=$(uptime | awk -F'load average:' '{print $2}' | awk
'{print $1}')
memoria_libre=$(free -h 2>/dev/null | grep Mem | awk '{print
$4}' || echo "N/A")
# Escribir estado
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sistema OK - Carga: $carga - Memoria libre: $memoria_libre" >> "$log_file"
Versión simplificada:
#!/bin/bash
# sistema_ok_simple.sh
archivo="$HOME/sistema_ok.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sistema OK" >> "$archivo"
Configurar crontab:
# 1. Crear el script (versión simple)
nano ~/sistema_ok.sh
chmod +x ~/sistema_ok.sh
# 2. Probar
~/sistema_ok.sh
cat ~/sistema_ok.log
# 3. Editar crontab
crontab -e
# 4. Añadir para ejecutar cada 10 minutos:
*/10 * * * * $HOME/sistema_ok.sh
# 5. Verificar
crontab -l
# 6. Monitorear
tail -f ~/sistema_ok.logOtros intervalos útiles:
/10 * * * = Cada 10 minutos
/15 * * * = Cada 15 minutos
0,10,20,30,40,50 * * * * = Cada 10 minutos (alternativa)
0-59/10 * * * * = Cada 10 minutos (alternativa)
- Crea un script que genere un archivo con la fecha actual. Prográmalo para ejecutarse el primer da de cada mes a medianoche.
#!/bin/bash
# Nombre: reporte_mensual.sh
# Descripción: Genera archivo de reporte mensual
# Directorio de reportes
dir_reportes="$HOME/reportes_mensuales"
mkdir -p "$dir_reportes"
# Generar nombre de archivo con fecha
fecha=$(date '+%Y-%m-%d')
mes_anio=$(date '+%Y-%m')
archivo="$dir_reportes/reporte_${mes_anio}.txt"
# Crear contenido del reporte
{
echo "======================================"
echo "REPORTE MENSUAL"
echo "======================================"
echo "Fecha de generación: $fecha"
echo "Hora: $(date '+%H:%M:%S')"
echo ""
echo "Sistema: $(uname -s)"
echo "Usuario: $USER"
echo "Hostname: $(hostname)"
echo ""
echo "Directorio home: $HOME"
echo "Espacio en disco:"
df -h "$HOME" | tail -1
echo ""
echo "======================================"
} > "$archivo"
# Log de ejecución
log_file="$HOME/reportes_mensuales/ejecucion.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Reporte mensual generado: $archivo" >> "$log_file"
Configurar crontab:
# 1. Crear el script
nano ~/reporte_mensual.sh
chmod +x ~/reporte_mensual.sh
# 2. Probar manualmente
~/reporte_mensual.sh
ls -lh ~/reportes_mensuales/
cat ~/reportes_mensuales/reporte_*.txt
# 3. Editar crontab
crontab -e4. Añadir para ejecutar el día 1 de cada mes a medianoche:
0 0 1 * * $HOME/reporte_mensual.sh
# 5. Verificar
crontab -lExplicación de cron mensual:
0 0 1 * * = Día 1 de cada mes a medianoche
0 0 15 * * = Día 15 de cada mes a medianoche
0 0 1,15 * * = Día 1 y 15 de cada mes a medianoche
0 0 1 1 * = El 1 de enero a medianoche (anualmente)
0 0 1 /3 = Primer día cada 3 meses (trimestral)
Para el último día del mes no hay atajo: la
L que verás en algunos sitios es de Quartz (el planificador
de Java) y el cron de Linux y macOS no la entiende; da
error de sintaxis. Lo que se hace es lanzarlo todos los días candidatos
y comprobar dentro si mañana es día 1:
55 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && $HOME/cierre_mes.shPrecaución
Fíjate en el
\%d, con barra invertida. Dentro de un crontab, el símbolo%no es un porcentaje: significa «salto de línea», y todo lo que venga detrás del primero se le pasa al comando como si lo hubieras tecleado.Por eso una línea como esta no funciona en el crontab:
* * * * * echo "$(date +%Y-%m-%d)" >> ~/registro.logHay que escapar cada
%con\, o —mucho mejor y más legible— meter el comando dentro de un script.shy llamar al script desde el crontab. Dentro del.shel%se comporta con normalidad.Es la causa número uno de «mi cron no funciona y no sé por qué».
- Configura un script que escriba “Probando cron” en un archivo. Después, buscar información para revisar los logs del sistema y confirmar su ejecución.
#!/bin/bash
# Nombre: probar_cron.sh
# Descripción: Script de prueba para verificar cron
# Archivo de salida
archivo="$HOME/prueba_cron.log"
# Escribir mensaje
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Probando cron - Ejecución exitosa" >> "$archivo"Escribir también en salida estándar para que aparezca en logs de
cron
echo “Cron ejecutado correctamente a las $(date ‘+%H:%M:%S’)”
Configurar y verificar:
# 1. Crear el script
nano ~/probar_cron.sh
chmod +x ~/probar_cron.sh
# 2. Probar manualmente
~/probar_cron.sh
cat ~/prueba_cron.log
# 3. Editar crontab
crontab -e
# 4. Añadir para ejecutar cada 5 minutos (para prueba rápida):
*/5 * * * * $HOME/probar_cron.sh
# 5. Verificar que se añadió
crontab -lRevisar logs del sistema para confirmar ejecución:
En Linux:
Ver logs de cron (varias ubicaciones según distribución)
sudo tail -f /var/log/cron
sudo tail -f /var/log/cron.log
sudo tail -f /var/log/syslog | grep CRON
Buscar ejecuciones de tu script
grep probar_cron /var/log/syslog
grep CRON /var/log/syslog | grep $USER
Ver logs con journalctl (systemd)
sudo journalctl -u cron.service -f
sudo journalctl -u cron.service –since “10 minutes ago”
En macOS:
Ver logs de cron en macOS
log show –predicate ‘process == “cron”’ –last 1h
log show –predicate ‘eventMessage contains “probar_cron”’ –last 30m
# Logs del sistema
tail -f /var/log/system.log | grep cron
# Verificar que cron está corriendo
ps aux | grep cronComandos útiles para debugging:
# Ver tu crontab actual
crontab -l
# Ver el archivo de salida del script
cat ~/prueba_cron.log
# Ver en tiempo real las nuevas líneas
tail -f ~/prueba_cron.log
# Verificar permisos del script
ls -l ~/probar_cron.sh
# Verificar que cron está activo
# Linux:
sudo systemctl status cron
# o
sudo service cron status
# macOS:
sudo launchctl list | grep cron
# Ver todas las tareas cron del sistema (root)
sudo crontab -l
# Editar variables de entorno en crontab (si necesario)
crontab -e
# Añadir al inicio:
# PATH=/usr/local/bin:/usr/bin:/bin
# SHELL=/bin/bashTroubleshooting command:
# Si cron no ejecuta el script:
# 1. Verificar que el script tiene permisos de ejecución
chmod +x ~/probar_cron.sh
# 2. Usar rutas absolutas en crontab
# Correcto: /home/usuario/probar_cron.sh
# Incorrecto: ~/probar_cron.sh
# 3. Redirigir salida y errores para debug
*/5 * * * * $HOME/probar_cron.sh >> $HOME/cron_debug.log
2>&1
# 4. Verificar que el servicio cron está corriendo
sudo systemctl start cron # Linux
# En macOS cron siempre está activo
# 5. Verificar sintaxis del crontab
# Después de editar, si hay errores, crontab te avisará