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