Operaciones con Archivos

Domina las herramientas avanzadas para búsqueda, manipulación y sincronización de archivos en sistemas Linux

Módulo 6 ⏱️ 35-40 min 🔍 Búsqueda 🔄 Sincronización 📚 Intermedio

Búsqueda Avanzada con Find

El comando find es una herramienta extremadamente poderosa para buscar archivos y directorios basándose en múltiples criterios como nombre, tipo, tamaño, permisos, fechas de modificación y más.

1. Sintaxis básica y criterios de búsqueda

Comandos básicos de find Copiar
#!/bin/bash

# Búsqueda por nombre
find /ruta -name "*.txt"                # Buscar archivos .txt
find . -iname "*.JPG"                   # Búsqueda insensible a mayúsculas

# Búsqueda por tipo
find /home -type f                      # Solo archivos regulares
find /home -type d                      # Solo directorios
find /home -type l                      # Solo enlaces simbólicos

# Búsqueda por tamaño
find . -size +100M                      # Archivos mayores a 100MB
find . -size -1k                       # Archivos menores a 1KB
find . -size 50c                       # Archivos exactamente de 50 bytes

# Búsqueda por tiempo
find . -mtime -7                       # Modificados en los últimos 7 días
find . -atime +30                      # Accedidos hace más de 30 días
find . -ctime -1                       # Cambiados en las últimas 24 horas

# Búsqueda por permisos
find . -perm 755                       # Permisos exactos
find . -perm -644                      # Al menos estos permisos
find . -perm /u+x                      # Ejecutable por el propietario

2. Combinando criterios y acciones

Find con operadores lógicos Copiar
#!/bin/bash

# Operadores lógicos
find . -name "*.log" -and -size +1M    # AND: archivos .log mayores a 1MB
find . -name "*.tmp" -or -name "*.cache" # OR: archivos .tmp o .cache
find . -not -name "*.bak"              # NOT: todo excepto .bak

# Acciones con los resultados
find . -name "*.log" -delete           # Eliminar archivos encontrados
find . -name "*.txt" -exec ls -la {} \;  # Ejecutar comando en cada archivo
find . -name "*.sh" -exec chmod +x {} \; # Hacer ejecutables scripts

# Acciones avanzadas
find . -name "*.tmp" -exec rm -i {} \;  # Eliminar con confirmación
find . -type f -exec wc -l {} + | sort -n  # Contar líneas y ordenar

# Usando -printf para formato personalizado
find . -name "*.txt" -printf "%f %s %TY-%Tm-%Td\n"  # Nombre, tamaño, fecha
Optimización de Find
  • Usa -prune para excluir directorios innecesarios
  • Coloca criterios más restrictivos primero
  • Usa -maxdepth para limitar la profundidad
  • Considera locate para búsquedas por nombre

Locate - Búsqueda Rápida

locate utiliza una base de datos pre-indexada para realizar búsquedas extremadamente rápidas por nombre de archivo. Es ideal para búsquedas frecuentes en sistemas con muchos archivos.

Comandos locate Copiar
#!/bin/bash

# Búsqueda básica
locate archivo.txt                     # Buscar por nombre
locate "*.conf"                        # Buscar con patrones

# Opciones útiles
locate -i config                       # Búsqueda insensible a mayúsculas  
locate -c "*.log"                      # Contar resultados
locate -l 10 "*.pdf"                  # Limitar a 10 resultados

# Actualizar base de datos (como root)
sudo updatedb                          # Actualizar índice completo
sudo updatedb --localpaths=/home       # Actualizar solo /home

# Búsqueda con expresiones regulares
locate -r '\.conf$'                    # Archivos que terminan en .conf
locate -r '/etc/.*\.d/'                # Directorios .d en /etc

# Información de la base de datos
locate -S                              # Estadísticas de la base de datos

Rsync - Sincronización Avanzada

rsync es la herramienta estándar para sincronización eficiente de archivos, tanto localmente como entre sistemas remotos. Utiliza algoritmos inteligentes para transferir solo las diferencias.

1. Sincronización básica

Comandos básicos de rsync Copiar
#!/bin/bash

# Sincronización local
rsync -av origen/ destino/              # Básico con archivos y verboso
rsync -av --delete origen/ destino/     # Eliminar archivos extra en destino

# Sincronización remota
rsync -av usuario@servidor:ruta/ local/  # Desde servidor remoto
rsync -av local/ usuario@servidor:ruta/  # Hacia servidor remoto

# Opciones importantes
rsync -avz origen/ destino/             # Con compresión (-z)
rsync -av --progress origen/ destino/    # Mostrar progreso
rsync -av --dry-run origen/ destino/    # Simulación sin ejecutar

# Exclusiones
rsync -av --exclude="*.tmp" origen/ destino/
rsync -av --exclude-from="excluir.txt" origen/ destino/

# Preservar atributos
rsync -avH origen/ destino/             # Preservar hard links
rsync -avX origen/ destino/             # Preservar atributos extendidos

2. Script avanzado de sincronización

Script completo de sincronización Copiar
#!/bin/bash
# advanced_sync.sh - Sistema avanzado de sincronización

# Configuración
SOURCE_DIR="/datos/importante"
BACKUP_DIR="/backup/incremental"
REMOTE_HOST="backup.servidor.com"
REMOTE_USER="backup"
REMOTE_PATH="/backup/remoto"
LOG_FILE="/var/log/sync.log"
LOCK_FILE="/tmp/sync.lock"
EMAIL="[email protected]"

# Opciones de rsync
RSYNC_OPTS="-avz --delete --partial --inplace"
EXCLUDE_FILE="/etc/rsync/exclude.txt"

log_message() {
    local level="$1"
    local message="$2"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" | tee -a "$LOG_FILE"
}

check_lock() {
    if [[ -f "$LOCK_FILE" ]]; then
        local pid=$(cat "$LOCK_FILE")
        if kill -0 "$pid" 2>/dev/null; then
            log_message "ERROR" "Sincronización ya en curso (PID: $pid)"
            exit 1
        else
            log_message "WARN" "Archivo de bloqueo obsoleto, eliminando"
            rm -f "$LOCK_FILE"
        fi
    fi
    
    echo $$ > "$LOCK_FILE"
}

cleanup() {
    rm -f "$LOCK_FILE"
    log_message "INFO" "Limpieza completada"
}

trap cleanup EXIT

verify_source() {
    if [[ ! -d "$SOURCE_DIR" ]]; then
        log_message "ERROR" "Directorio fuente no existe: $SOURCE_DIR"
        return 1
    fi
    
    if [[ ! -r "$SOURCE_DIR" ]]; then
        log_message "ERROR" "Sin permisos de lectura en: $SOURCE_DIR"
        return 1
    fi
    
    log_message "INFO" "Directorio fuente verificado: $SOURCE_DIR"
    return 0
}

create_backup_structure() {
    local current_backup="$BACKUP_DIR/current"
    local today_backup="$BACKUP_DIR/$(date +%Y-%m-%d)"
    
    # Crear directorio de backup si no existe
    mkdir -p "$BACKUP_DIR"
    
    # Si existe backup actual, crear hard links para backup incremental
    if [[ -d "$current_backup" ]]; then
        log_message "INFO" "Creando backup incremental en: $today_backup"
        cp -al "$current_backup" "$today_backup"
    else
        log_message "INFO" "Creando primer backup completo"
        mkdir -p "$current_backup"
        today_backup="$current_backup"
    fi
    
    echo "$today_backup"
}

sync_local() {
    local target="$1"
    
    log_message "INFO" "Iniciando sincronización local"
    log_message "INFO" "Origen: $SOURCE_DIR"
    log_message "INFO" "Destino: $target"
    
    local rsync_cmd="rsync $RSYNC_OPTS"
    
    if [[ -f "$EXCLUDE_FILE" ]]; then
        rsync_cmd="$rsync_cmd --exclude-from=$EXCLUDE_FILE"
    fi
    
    rsync_cmd="$rsync_cmd \"$SOURCE_DIR/\" \"$target/\""
    
    log_message "INFO" "Ejecutando: $rsync_cmd"
    
    if eval "$rsync_cmd"; then
        log_message "INFO" "Sincronización local completada exitosamente"
        
        # Actualizar enlace current
        if [[ "$target" != "$BACKUP_DIR/current" ]]; then
            rm -f "$BACKUP_DIR/current"
            ln -sf "$(basename "$target")" "$BACKUP_DIR/current"
        fi
        
        return 0
    else
        local exit_code=$?
        log_message "ERROR" "Sincronización local falló con código: $exit_code"
        return $exit_code
    fi
}

sync_remote() {
    if [[ -z "$REMOTE_HOST" ]]; then
        log_message "INFO" "Sincronización remota deshabilitada"
        return 0
    fi
    
    log_message "INFO" "Iniciando sincronización remota"
    log_message "INFO" "Servidor: $REMOTE_HOST"
    
    # Verificar conectividad
    if ! ping -c 1 -W 5 "$REMOTE_HOST" >/dev/null 2>&1; then
        log_message "ERROR" "No se puede conectar a: $REMOTE_HOST"
        return 1
    fi
    
    local rsync_cmd="rsync $RSYNC_OPTS -e ssh"
    
    if [[ -f "$EXCLUDE_FILE" ]]; then
        rsync_cmd="$rsync_cmd --exclude-from=$EXCLUDE_FILE"
    fi
    
    rsync_cmd="$rsync_cmd \"$SOURCE_DIR/\" \"$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/\""
    
    log_message "INFO" "Ejecutando sincronización remota"
    
    if eval "$rsync_cmd"; then
        log_message "INFO" "Sincronización remota completada exitosamente"
        return 0
    else
        local exit_code=$?
        log_message "ERROR" "Sincronización remota falló con código: $exit_code"
        return $exit_code
    fi
}

cleanup_old_backups() {
    local retention_days=${1:-7}
    
    log_message "INFO" "Limpiando backups antiguos (>${retention_days} días)"
    
    find "$BACKUP_DIR" -maxdepth 1 -type d -name "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" \
        -mtime +$retention_days -exec rm -rf {} \;
    
    log_message "INFO" "Limpieza de backups completada"
}

send_report() {
    local status="$1"
    local details="$2"
    
    if [[ -n "$EMAIL" ]] && command -v mail >/dev/null 2>&1; then
        local subject="Reporte de Sincronización - $status"
        echo -e "Reporte de sincronización:\n\n$details\n\nLog completo en: $LOG_FILE" | \
            mail -s "$subject" "$EMAIL"
    fi
}

generate_statistics() {
    local backup_dir="$1"
    
    log_message "INFO" "Generando estadísticas"
    
    if [[ -d "$backup_dir" ]]; then
        local total_files=$(find "$backup_dir" -type f | wc -l)
        local total_size=$(du -sh "$backup_dir" | cut -f1)
        local disk_usage=$(df -h "$BACKUP_DIR" | awk 'NR==2 {print "Usado: "$3" de "$2" ("$5")"}')
        
        echo "=== Estadísticas del Backup ==="
        echo "Archivos: $total_files"
        echo "Tamaño total: $total_size"
        echo "Espacio en disco: $disk_usage"
        echo "Ubicación: $backup_dir"
    fi
}

# Función principal
main() {
    log_message "INFO" "=== Iniciando proceso de sincronización ==="
    
    # Verificaciones previas
    check_lock
    
    if ! verify_source; then
        log_message "ERROR" "Verificación de origen falló"
        send_report "ERROR" "Verificación de origen falló"
        exit 1
    fi
    
    # Crear estructura de backup
    local backup_target
    backup_target=$(create_backup_structure)
    
    local sync_errors=0
    
    # Sincronización local
    if ! sync_local "$backup_target"; then
        ((sync_errors++))
    fi
    
    # Sincronización remota
    if ! sync_remote; then
        ((sync_errors++))
    fi
    
    # Limpieza de backups antiguos
    cleanup_old_backups 7
    
    # Generar estadísticas
    local stats=$(generate_statistics "$backup_target")
    
    # Reporte final
    if [[ $sync_errors -eq 0 ]]; then
        log_message "INFO" "Todas las sincronizaciones completadas exitosamente"
        send_report "ÉXITO" "$stats"
    else
        log_message "ERROR" "$sync_errors sincronización(es) fallaron"
        send_report "ERROR" "Se encontraron $sync_errors errores. $stats"
    fi
    
    log_message "INFO" "=== Proceso de sincronización finalizado ==="
    echo "$stats"
    
    return $sync_errors
}

# Procesamiento de argumentos
case "${1:-run}" in
    "run")
        main
        ;;
    "test")
        echo "Modo de prueba - configuración actual:"
        echo "Origen: $SOURCE_DIR"
        echo "Backup local: $BACKUP_DIR"
        echo "Remoto: $REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH"
        ;;
    "status")
        if [[ -f "$LOCK_FILE" ]]; then
            echo "Sincronización en curso (PID: $(cat "$LOCK_FILE"))"
        else
            echo "No hay sincronización activa"
        fi
        echo "Último backup: $(ls -la "$BACKUP_DIR/current" 2>/dev/null || echo 'No encontrado')"
        ;;
    *)
        echo "Uso: $0 [run|test|status]"
        echo ""
        echo "  run    - Ejecutar sincronización completa"
        echo "  test   - Mostrar configuración"
        echo "  status - Ver estado actual"
        ;;
esac

Otras Herramientas de Manipulación

Además de find y rsync, Linux proporciona muchas otras herramientas útiles para manipular y gestionar archivos de forma eficiente.

Herramientas adicionales Copiar
#!/bin/bash

# RENAME - Renombrado masivo
rename 's/\.jpeg$/\.jpg/' *.jpeg       # Cambiar extensión jpeg a jpg
rename 'y/A-Z/a-z/' *.TXT             # Convertir a minúsculas

# STAT - Información detallada de archivos
stat archivo.txt                       # Información completa
stat -c '%n %s %y' *.txt              # Formato personalizado

# FILE - Detectar tipo de archivo
file archivo                          # Tipo de archivo
file -b archivo                       # Solo la descripción
file -i archivo                       # Tipo MIME

# DU - Uso de disco
du -sh directorio/                    # Tamaño total
du -ah directorio/ | sort -hr         # Tamaños ordenados

# TREE - Estructura de directorios
tree directorio/                      # Árbol completo
tree -L 2 directorio/                 # Máximo 2 niveles
tree -P "*.txt" directorio/           # Solo archivos .txt

# XARGS - Procesamiento en lotes
find . -name "*.log" | xargs grep "error"  # Buscar en múltiples archivos
find . -name "*.tmp" | xargs -I {} mv {} /tmp/  # Mover archivos

# PARALLEL - Procesamiento paralelo
find . -name "*.jpg" | parallel -j4 convert {} {.}.png  # Conversión paralela
Precauciones Importantes
  • Siempre haz pruebas: Usa --dry-run o -n cuando esté disponible
  • Backups antes de cambios masivos: Especialmente con rename y operaciones destructivas
  • Verifica permisos: Asegúrate de tener los permisos correctos antes de ejecutar
  • Cuidado con espacios: Usa comillas adecuadas en nombres con espacios

Ejercicios Prácticos

Ejercicio 1: Buscador Inteligente

Crea un script que:

  • Busque archivos por múltiples criterios combinados
  • Genere reportes de uso de espacio
  • Identifique duplicados por contenido
  • Proporcione estadísticas detalladas
Ejercicio 2: Sistema de Sincronización

Desarrolla una herramienta que:

  • Sincronice múltiples ubicaciones
  • Maneje conflictos automáticamente
  • Genere logs detallados
  • Envíe notificaciones por email
Ejercicio 3: Organizador Automático

Implementa un sistema que:

  • Organice archivos por tipo y fecha
  • Aplique reglas de nomenclatura consistentes
  • Comprima archivos antiguos automáticamente
  • Mantenga estructura organizada