En algún lugar, ahora mismo, un trabajo de copia de seguridad está “verde” mientras omite archivos sin que nadie lo note. Otro equipo está entregando una versión construida desde una carpeta que “debería coincidir con producción”. Y alguien está a punto de copiar un terabyte dos veces porque no confía en la primera copia.
Comparar dos carpetas suena como una tarea básica. En producción es una trampilla. El método correcto depende de lo que estés demostrando: existencia, identidad byte a byte, o “suficientemente igual” para un despliegue. Elegir mal te da o confianza falsa o una respuesta cara y lenta que llega cuando ya pasó el incidente.
Qué estás realmente demostrando (y por qué importa)
“Comparar dos carpetas” no es un solo problema. Son al menos cinco. Si no dices cuál quieres resolver, acabarás por defecto con algo lento (hashear todo) o engañoso (confiar en tamaños de archivo). Aquí está la taxonomía que uso en las guardias.
1) Existencia: ¿están presentes todos los archivos esperados?
Este es el problema de “archivos faltantes”: una copia parcial, una copia de seguridad fallida, una sincronización de artefactos incompleta. Te importan los nombres de archivo y quizá la estructura de directorios. Normalmente aún no te importan los contenidos de los archivos.
Buenas herramientas: rsync --dry-run, comm sobre listas de archivos ordenadas, manifiestos con find.
2) Igualdad de metadatos: ¿coinciden timestamps, permisos y propiedad?
Esto importa cuando estás restaurando sistemas, migrando directorios home o moviendo datos entre servidores NFS donde los modos y propietarios son los “datos reales”. Si los permisos difieren, tu aplicación falla de maneras que parecen “caídas aleatorias”. No son aleatorias.
Buenas herramientas: rsync -a --dry-run, stat, getfacl si las ACL importan.
3) Igualdad de contenido: ¿son los bytes idénticos?
Esto es verificación de integridad. Estás demostrando que dos archivos son iguales incluso si timestamps o nombres mienten. Es más lento, pero es lo único que cierra discusiones después de una restauración.
Buenas herramientas: checksums (SHA-256), rsync --checksum (con precaución), muestreo de contenido cuando tienes límite de tiempo.
4) Igualdad lógica: ¿producen el mismo resultado?
Para builds, contenedores y conjuntos de datos, puede que no te importe la igualdad byte a byte. Te importa si la aplicación se comporta igual. Esa es otra prueba. La comparación de carpetas puede ayudar, pero no confundas “parece igual” con “es igual”.
5) Consistencia bajo cambio: ¿estás comparando un objetivo en movimiento?
Comparar una carpeta mientras se escriben archivos es como medir un pez mientras se escapa. A veces puedes hacerlo (snapshots, quiescencia, builds inmutables). A veces no, y la respuesta correcta es “detener el mundo y luego comparar”.
Una cita operativa para recordar:
Idea parafraseada — Gene Kim: las operaciones de alto rendimiento acortan los bucles de retroalimentación y hacen el trabajo visible, de modo que los problemas aparecen antes de convertirse en incidentes.
La comparación de carpetas es visibilidad. No es glamorosa. Pero es la diferencia entre “creemos que se copió” y “podemos demostrar que se copió”.
Métodos rápidos primero: elegir la herramienta adecuada
Regla #1: no hashees un petabyte porque estás nervioso
Los checksums son el estándar de oro, pero también son el impuesto de “leer cada byte”. Si tu única pregunta es “¿faltó algo?”, hashear es autolesionarse. Empieza con un manifiesto de rutas relativas y tamaños; luego escala.
Regla #2: rsync --dry-run es la herramienta de “comparar carpetas” más útil del planeta
Habla el idioma de operaciones: “¿Qué cambiaría si sincronizo esto?” Eso es un diff con consecuencias. Úsalo localmente, por SSH, entre puntos de montaje. Cuando hay presión, te da una lista accionable.
Regla #3: los timestamps suelen mentir
Las herramientas de copia preservan mtimes a veces, a veces no. Los sistemas de archivos redondean mtimes de formas distintas. Cambios de zona horaria y deriva de reloj ocurren. Si comparas mtimes, trata los resultados como pista, no como veredicto.
Regla #4: permisos y ACL son datos
Si estás restaurando un servicio, la propiedad incorrecta es “pérdida de datos” con mejor marketing. Si tu comparación ignora las ACL, vas a entregar un problema y llamarlo restauración exitosa.
Regla #5: si el conjunto de datos está vivo, usa snapshots (o acepta incertidumbre)
En ZFS, los snapshots lo hacen fácil. En LVM, también puedes hacerlo. En almacenamiento de objetos en la nube, necesitarás manifiestos versionados. Sin una vista estable en un punto en el tiempo, tu comparación mostrará cambios que son solo escrituras de hoy.
Broma #1: Hashear todo “por seguridad” es como pesar tu coche cada mañana para comprobar el indicador de combustible. Exacto, sí. Necesario, no.
Tareas prácticas (comandos, salidas, decisiones)
A continuación hay tareas aptas para producción. Cada una incluye un comando, un fragmento de salida realista y la decisión que tomas a partir de ello. Ejecútalas con un objetivo claro: encontrar archivos faltantes, archivos cambiados, deriva de metadatos o problemas de integridad.
Task 1: Detección rápida de archivos faltantes con rsync (local a local)
cr0x@server:~$ rsync -a --dry-run --itemize-changes /data/src/ /data/dst/
sending incremental file list
*deleting old/unused.log
>f+++++++++ reports/2026-01.csv
>f..t...... images/logo.png
sent 1,204 bytes received 88 bytes 2,584.00 bytes/sec
total size is 9,812,441,102 speedup is 7,589,904.72 (DRY RUN)
Qué significa: >f+++++++++ es un archivo que se crearía en el destino (está ausente allí). >f..t...... significa que la timestamp difiere (el contenido puede o no). *deleting indica que el destino tiene archivos extra que no están en la fuente (solo se muestra si añades banderas de borrado; ver siguiente tarea).
Decisión: Si estás verificando una copia, los archivos faltantes (+++++++++) son un problema crítico. Las diferencias solo en timestamp requieren comprobaciones adicionales (tamaño/hash) según tu tolerancia al riesgo.
Task 2: Detectar extras en el destino (de forma segura) con rsync
cr0x@server:~$ rsync -a --dry-run --delete --itemize-changes /data/src/ /data/dst/
sending incremental file list
*deleting tmp/debug.dump
*deleting cache/.DS_Store
sent 1,112 bytes received 64 bytes 2,352.00 bytes/sec
total size is 9,812,441,102 speedup is 8,342,119.31 (DRY RUN)
Qué significa: Con --delete, rsync propondrá borrar archivos en el destino que no están en la fuente. En dry-run, solo informa.
Decisión: Si el destino debe ser un espejo (backups, réplicas), esos extras son deriva. Si el destino es un archivo, probablemente no quieras la semántica de borrado.
Task 3: Comparar dos directorios rápidamente con diff -rq
cr0x@server:~$ diff -rq /data/src /data/dst | head
Only in /data/src/reports: 2026-01.csv
Files /data/src/images/logo.png and /data/dst/images/logo.png differ
Only in /data/dst/tmp: debug.dump
Qué significa: Archivos faltantes y líneas de “differ”. diff compara contenido, pero lee archivos; en árboles enormes puede ser más lento que la detección basada en metadatos de rsync.
Decisión: Usa esto cuando necesites un informe directo “igual/diferente” y el conjunto de datos sea moderado. Si es multi-terabyte, prefiere manifiestos de rsync y hashing dirigido.
Task 4: Construir un manifiesto estable de rutas y tamaños (barato, generalmente suficiente)
cr0x@server:~$ cd /data/src
cr0x@server:~$ find . -type f -printf '%P\t%s\n' | sort > /tmp/src.pathsizes
cr0x@server:~$ wc -l /tmp/src.pathsizes
84217 /tmp/src.pathsizes
Qué significa: Una línea por archivo: ruta relativa y tamaño. Ordenar lo hace comparable.
Decisión: Si los manifiestos de src y dst coinciden exactamente, has demostrado “mismos archivos, mismos tamaños”. No son idénticos por bytes, pero es evidencia sólida para copias donde la corrupción es improbable y el tiempo es limitado.
Task 5: Comparar manifiestos con comm para encontrar archivos faltantes
cr0x@server:~$ cd /data/dst
cr0x@server:~$ find . -type f -printf '%P\t%s\n' | sort > /tmp/dst.pathsizes
cr0x@server:~$ comm -3 /tmp/src.pathsizes /tmp/dst.pathsizes | head
reports/2026-01.csv 12044
tmp/debug.dump 4096
Qué significa: Líneas con tabulación prefija existen solo en el segundo archivo; líneas sin tabulación existen solo en el primero. Aquí: report faltante en dst; debug.dump extra en dst.
Decisión: Archivos faltantes: recopia o resync. Archivos extra: decide si dst debe ser espejo exacto; si es así, borra o reconstruye dst desde la fuente de la verdad.
Task 6: Identificar “misma ruta, distinto tamaño” rápidamente
cr0x@server:~$ join -t $'\t' -j 1 \
<(cut -f1,2 /tmp/src.pathsizes) \
<(cut -f1,2 /tmp/dst.pathsizes) | awk -F'\t' '$2 != $3 {print $1, $2, $3}' | head
images/logo.png 18432 18312
db/seed.sql 901122 901114
Qué significa: La misma ruta relativa existe en ambos, pero los tamaños difieren.
Decisión: Trátalo como contenido cambiado. Si debe ser idéntico, resync esas rutas y luego hasheálas para confirmar.
Task 7: Hash dirigido solo de archivos sospechosos (escalada rápida)
cr0x@server:~$ sha256sum /data/src/images/logo.png /data/dst/images/logo.png
a1c3d2d19c9f7f0c2a2a0ddc7f6d4b2e9f1b2d3c4a5b6c7d8e9f001122334455 /data/src/images/logo.png
b88f2bd42a9e0f1c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c /data/dst/images/logo.png
Qué significa: Hashes diferentes: bytes diferentes, punto final.
Decisión: Si dst es backup/replica, investiga corrupción en la transferencia/almacenamiento o una actualización desincronizada. Si es un artefacto de despliegue, detén y reconstruye desde la fuente de la verdad única.
Task 8: Manifiesto de checksums de todo el árbol (lento, definitivo)
cr0x@server:~$ cd /data/src
cr0x@server:~$ find . -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/src.sha256
cr0x@server:~$ head -3 /tmp/src.sha256
9f2a... ./bin/app
44c1... ./conf/app.yaml
e11b... ./images/logo.png
Qué significa: Manifiesto de checksums ordenado y estable para todo el árbol. Ordenar con separadores nulos evita problemas con rutas extrañas y deriva en el orden.
Decisión: Usa esto cuando necesites prueba de grado legal (restauraciones, cumplimiento, promoción de artefactos). Acepta que es intensivo en E/S; prográmalo, no sorprendas producción.
Task 9: Verificar que el destino coincida con un manifiesto de checksums
cr0x@server:~$ cd /data/dst
cr0x@server:~$ sha256sum -c /tmp/src.sha256 | head
./bin/app: OK
./conf/app.yaml: OK
./images/logo.png: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
Qué significa: OK significa coincidencia exacta. FAILED significa que el contenido difiere. Si aparece “No such file”, el archivo falta.
Decisión: Cualquier FAILED o archivo faltante es un fallo grave para la verificación de backups. Recopia esos archivos; si los fallos persisten, sospecha problemas de almacenamiento/medio o corrupción silenciosa.
Task 10: Comparar carpetas por SSH con rsync (dry-run)
cr0x@server:~$ rsync -a --dry-run --itemize-changes -e ssh /data/src/ backup01:/data/dst/
sending incremental file list
>f+++++++++ reports/2026-01.csv
>f..t...... images/logo.png
sent 1,882 bytes received 112 bytes 3,988.00 bytes/sec
total size is 9,812,441,102 speedup is 4,920,184.83 (DRY RUN)
Qué significa: Mismas semánticas, pero ahora estás validando estado remoto. Nota: rsync compara metadatos por defecto, no checksums.
Decisión: Úsalo como auditoría remota de primera pasada. Si aparece algo sorprendente, haz hashing dirigido por SSH de los archivos sospechosos (o genera manifiesto en cada lado).
Task 11: Detectar deriva de permisos (la clase “existe pero no funciona”)
cr0x@server:~$ stat -c '%a %U:%G %n' /data/src/conf/app.yaml /data/dst/conf/app.yaml
640 app:app /data/src/conf/app.yaml
600 app:app /data/dst/conf/app.yaml
Qué significa: Mismo propietario, modos distintos. Eso puede romper lecturas, escrituras o expectativas de gestión de configuración.
Decisión: Si los permisos deben coincidir, corrige tu método de copia: rsync -a (y ejecútalo como root cuando la propiedad importe), o preserva ACLs/xattrs si tu entorno los usa.
Task 12: Comparar atributos extendidos (xattrs) cuando importan
cr0x@server:~$ getfattr -d -m - /data/src/bin/app 2>/dev/null
# file: data/src/bin/app
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
cr0x@server:~$ getfattr -d -m - /data/dst/bin/app 2>/dev/null
# file: data/dst/bin/app
Qué significa: La fuente tiene un xattr de capacidad de Linux; el destino no. El binario puede fallar al enlazarse a puertos bajos o comportarse de forma distinta.
Decisión: Usa rsync -aX (xattrs) y posiblemente -A (ACLs). Si estás en sistemas de archivos que eliminan xattrs, deja de pretender que es una copia fiel.
Task 13: Encontrar archivos cambiados recientemente (triage durante un incidente)
cr0x@server:~$ find /data/src -type f -mmin -60 -printf '%TY-%Tm-%Td %TH:%TM %p\n' | head
2026-02-05 09:12 /data/src/reports/2026-02.csv
2026-02-05 09:21 /data/src/tmp/run.log
Qué significa: Archivos modificados en la última hora. Genial para “¿por qué la comparación sigue cambiando?”.
Decisión: Si tu árbol está cambiando activamente, deja de compararlo en vivo. Usa snapshots, congela escrituras o compara solo subárboles inmutables (como artefactos de release).
Task 14: Chequeo rápido “¿estos directorios están en distintos sistemas de archivos con distintas semánticas?”
cr0x@server:~$ df -T /data/src /data/dst
Filesystem Type 1K-blocks Used Available Use% Mounted on
tank/data zfs 9767548928 512334112 9255214816 6% /data/src
backup:/data nfs4 9767548928 515220480 9252328448 6% /data/dst
Qué significa: La fuente es ZFS; el destino es NFS. Espera distinta precisión de timestamps, mapeo raro de propietarios y caché de atributos.
Decisión: Si los resultados de la comparación son “ruidosos”, valida con checksums para archivos críticos y ajusta las opciones de montaje NFS si es necesario. Además: no asumas que las características POSIX se comportan idénticamente entre ellos.
Task 15: Medir el coste de tu método de comparación (no adivines)
cr0x@server:~$ /usr/bin/time -v rsync -a --dry-run /data/src/ /data/dst/ >/dev/null
Command being timed: "rsync -a --dry-run /data/src/ /data/dst/"
User time (seconds): 0.82
System time (seconds): 4.11
Percent of CPU this job got: 62%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:07.96
File system inputs: 126544
File system outputs: 0
Qué significa: Muchas entradas de sistema de archivos incluso en dry-run. Eso es I/O de metadatos. En cachés frías, esto puede saturar tu almacenamiento.
Decisión: Si los escaneos de metadatos están causando cuellos de botella en producción, programa comparaciones fuera de pico, calienta cachés con cuidado o mantén un manifiesto rodante actualizado incrementalmente.
Task 16: Cuando absolutamente necesitas comparar a nivel de byte un único archivo enorme
cr0x@server:~$ cmp -n 1048576 /data/src/big.img /data/dst/big.img && echo "first 1MiB matches"
first 1MiB matches
Qué significa: Los primeros 1 MiB coinciden. Esto no es verificación completa, pero es una comprobación de humo rápida cuando haces triage.
Decisión: Úsalo como prueba rápida, luego sigue con checksums completos si el archivo es crítico.
Broma #2: Nada construye más unidad de equipo que un archivo faltante descubierto cinco minutos antes de una demostración.
Guía rápida de diagnóstico
Cuando “la comparación de carpetas es lenta” o “los resultados no tienen sentido”, no te alteres. Diagnostica como un SRE: aisla el cuello de botella y luego elige la solución menos invasiva.
Primero: confirma el tipo de problema
- ¿Archivos faltantes? Usa
rsync -a --dry-runo manifiestos de rutas. No hashees aún. - ¿Contenido cambiado? Revisa deltas de tamaño/mtime y luego hashea solo el conjunto delta.
- ¿Problemas de permisos/ACL? Compara metadatos; hashear no ayudará.
- ¿Árbol en cambio activo? Deja de comparar objetivos en movimiento: snapshots o congelar escrituras.
Segundo: identifica qué es lento (CPU, I/O de metadatos, red o disco)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 02/05/2026 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
3.11 0.00 9.44 41.02 0.00 46.43
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s w_await aqu-sz %util
nvme0n1 821.0 66240.0 0.0 0.00 47.20 80.70 2.0 64.0 1.50 38.80 99.20
Interpretación: Alto %iowait y %util cerca de 100%: el almacenamiento es el cuello de botella. Los escaneos de directorios están castigando tus discos.
Acción: Deja de hacer escaneos de todo el árbol durante picos. Usa snapshots/manifiestos, o ejecuta comparaciones en una réplica/secundaria.
cr0x@server:~$ sar -n DEV 1 3 | tail -n +4
Average: IFACE rxpck/s txpck/s rxkB/s txkB/s %ifutil
Average: eth0 120.11 115.88 9821.33 9012.47 82.50
Interpretación: La red está ocupada; las comparaciones remotas pueden estar limitadas por la utilización del enlace o la latencia.
Acción: Prefiere la generación de manifiestos en el lado remoto y compara salidas de texto pequeñas. Evita leer archivos enteros por la red a menos que sea necesario.
Tercero: verifica semánticas del sistema de archivos y montajes
- La caché de atributos de NFS puede hacer que mtimes parezcan “incorrectos” temporalmente.
- SMB/CIFS puede normalizar mayúsculas/minúsculas; copias desde macOS pueden crear archivos AppleDouble.
- La distinta precisión de timestamps puede producir señales de “cambio” constantes.
cr0x@server:~$ mount | grep -E ' /data/dst | /data/src '
tank/data on /data/src type zfs (rw,xattr,noacl)
backup:/data on /data/dst type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2)
Interpretación: Plataformas diferentes. Espera casos límite de metadatos.
Acción: Si el objetivo es integridad, no discutas con los mtimes. Usa manifiestos de checksums para subconjuntos críticos.
Cuarto: reduce el alcance con inteligencia
- Compara solo directorios inmutables (releases, snapshots, particiones diarias).
- Excluye cachés y carpetas temporales; son generadores de entropía.
- Comienza con comparaciones “solo listar” y escala.
cr0x@server:~$ rsync -a --dry-run --itemize-changes --exclude='tmp/' --exclude='cache/' /data/src/ /data/dst/ | head
sending incremental file list
>f+++++++++ reports/2026-01.csv
Interpretación: La señal respecto al ruido mejora de inmediato.
Acción: Incorpora exclusiones en tus scripts estándar de comparación, pero documéntalas para no ocultar problemas reales.
Tres micro-historias corporativas (con dolor incluido)
Incidente causado por una suposición errónea: “coincidencia de tamaño significa coincidencia de contenido”
Un equipo migró un gran archivo de informes entre dos NAS. Usaron una comprobación rápida: conteo de archivos y bytes totales. Todo coincidía. Declararon victoria y desmantelaron el sistema antiguo.
Semanas después, los auditores pidieron un conjunto específico de informes mensuales. Un puñado no se podía leer: los PDFs daban errores. Los nombres de archivo existían y los tamaños coincidían. Eso lo hizo especialmente desagradable; nadie sospechó corrupción.
La causa raíz fue un camino de red inestable durante la copia original. La herramienta de copia reintentó y “completó”, pero algunos archivos se truncaron silenciosamente y luego una aplicación rellenó metadatos. Mismo tamaño. Bytes distintos. La comprobación de conteo no lo detectó; la de tamaño tampoco; la de timestamps tampoco.
La solución fue aburrida: generar un manifiesto SHA-256 en la fuente, verificarlo en el destino y solo entonces borrar el conjunto de datos antiguo. Rehidrataron los archivos corruptos desde copias más antiguas e implementaron verificación por checksum para futuras migraciones.
La lección: si vas a retirar la fuente de la verdad, haz al menos una pasada de verificación basada en contenido. No necesariamente para todo a diario, pero para migraciones, siempre.
Optimización que salió mal: “usemos --checksum en todas partes”
Un grupo de la plataforma se cansó de debatir si dos directorios “realmente” eran iguales. Envolvieron rsync en un script y usaron --checksum por defecto. En teoría, resolvía el problema de confianza: rsync hashearía cada archivo y compararía hashes.
En la práctica, movió el coste de “a veces re-copiamos demasiado” a “leemos todo el dataset en cada ejecución”. En un clúster de almacenamiento con alta presión de metadatos y discos ocupados, eso convirtió el trabajo de comparación en una denegación de servicio contra su propia infraestructura. La latencia subió. Las ventanas de backup se retrasaron. Algunos servicios empezaron a hacer timeouts contra el almacenamiento compartido.
Lo más irritante: el script corría como cron. Así que el radio de impacto era periódico y confuso, como una casa encantada pero con gráficos. Primero culparon a la red. Luego al proveedor de almacenamiento. Finalmente alguien ejecutó iostat durante el evento y vio la saturación de lecturas.
La solución fue una verificación por capas: usar la comparación de metadatos de rsync para chequeos diarios, y ejecutar un manifiesto de checksums semanalmente (o a demanda tras incidentes). También añadieron control de alcance: hashear solo artefactos de release inmutables y directorios críticos para cumplimiento.
La lección: “correcto” puede ser operativamente incorrecto si se aplica sin criterio. La verdad determinista es genial; las caídas deterministas no lo son.
Práctica aburrida pero correcta que salvó el día: snapshot + manifiesto
Un equipo de ingeniería de datos necesitaba replicar un conjunto de datos nocturno a un sitio de recuperación ante desastres. El dataset era grande y cambiaba constantemente durante el horario laboral. Los intentos tempranos de comparar directorios en vivo producían resultados inconsistentes: archivos aparecían y desaparecían a mitad de escaneo, y los diffs eran ruidosos.
Adoptaron una práctica estricta: a la 01:00, tomar snapshot del dataset fuente, replicar ese snapshot y luego comparar el contenido del snapshot con el snapshot replicado. Nada de comparaciones “en vivo”. Ninguna discusión sobre churn.
Un martes cualquiera, la replicación “tuvo éxito” pero los trabajos aguas abajo empezaron a fallar en DR. Su pipeline de comparación marcó un pequeño número de archivos faltantes en una partición. Como la comparación era contra un snapshot, fue inequívoco: los archivos faltaban en la vista replicada, no “todavía estaban siendo escritos”.
Encontraron el culpable rápido: un patrón de exclusión mal configurado en el trabajo de replicación que filtraba un nombre de directorio usado solo por un cliente. Se había introducido durante una limpieza. El pipeline de comparación lo detectó de inmediato, antes de que un desastre les obligara a depender de DR.
La lección: los snapshots convierten la comparación de opinión en matemáticas. La práctica es aburrida. Por eso funciona.
Hechos interesantes e historia útil
- La idea de “transferencia delta” de rsync data de mediados de los 90 y hizo que la sincronización remota fuera práctica en enlaces lentos al no re-enviar bloques sin cambios.
- Unix
diffes anterior a la mayoría de los sistemas de archivos modernos. Fue creado para texto, pero su modo recursivo se volvió una herramienta contundente para árboles de directorios. - MD5 solía ser común para chequear integridad, pero los ataques de colisión lo hicieron mala elección en contextos adversariales. Para verificación operativa, SHA-256 es la opción sensata.
- La precisión de timestamps varía: ext4 soporta nanosegundos; algunos sistemas de archivos en red redondean a 1 segundo (o peor). Tu señal de “cambio” puede ser ruido de redondeo.
- La sensibilidad a mayúsculas difiere: los sistemas de archivos Linux suelen ser case-sensitive; muchos Windows y configuraciones por defecto de macOS son case-insensitive. Dos archivos distintos pueden colapsar en uno durante una copia.
- Los hard links complican métricas de “conteo de archivos”: un inode puede tener múltiples entradas de directorio. Algunos métodos de copia duplican datos en lugar de preservar enlaces a menos que estén configurados.
- Atributos extendidos y ACLs se volvieron de uso común conforme los sistemas aumentaron su conciencia de seguridad; perderlos puede cambiar ejecución y acceso sin cambiar el contenido de archivos.
- La corrupción silenciosa de datos es real: los sistemas modernos dependen de verificaciones end-to-end (sistemas de archivos como ZFS, checksums en la aplicación o verificación por manifiesto) porque discos, controladoras y RAM pueden fallar ocasionalmente.
- “Backup completado” rara vez significa “restauración verificada”: la madurez operacional suele mostrarse como verificación rutinaria, no por paneles más bonitos.
Errores comunes: síntomas → causa raíz → solución
1) Síntoma: la comparación muestra miles de archivos “cambiados” en cada ejecución
Causa raíz: desajuste de precisión de timestamps (ext4 local vs NFS/SMB), deriva de tiempo o una herramienta de copia que no preserva mtimes.
Solución: Deja de confiar en mtimes como señal primaria. Usa manifiestos de tamaño primero; luego hashea los deltas. Si necesitas fidelidad de metadatos, usa rsync -a y asegúrate de que ambos lados lo soporten.
2) Síntoma: los archivos existen en el destino pero la app falla con “permission denied”
Causa raíz: propiedad/modo/ACL/xattr no preservados; restauración realizada como no-root; ACLs eliminadas por el sistema de archivos.
Solución: Usa rsync -aAX cuando corresponda. Valida con stat, getfacl, getfattr. Si el destino no puede almacenar ACLs/xattrs, cambia el destino o ajusta el modelo de seguridad intencionalmente.
3) Síntoma: archivos “Solo en la fuente” aparecen y desaparecen durante el escaneo
Causa raíz: comparar un directorio en vivo que está siendo escrito, rotado o limpiado.
Solución: Compara snapshots o detén las escrituras durante la comparación. Para logs y rutas temporales, exclúyelas del alcance de la comparación.
4) Síntoma: rsync muestra diferencias, pero el hashing muestra archivos idénticos
Causa raíz: diferencias de metadatos (mtime, permisos) o redondeo de timestamps; rsync dice la verdad sobre metadatos, no sobre contenido.
Solución: Decide qué significa “igual” para este flujo de trabajo. Para integridad de backups, el contenido importa más; para restauración de sistema, los metadatos también importan. Configura la comparación en consecuencia.
5) Síntoma: la verificación por checksum es intolerablemente lenta e impacta producción
Causa raíz: lectura completa de grandes datasets, cachés frías, contención con I/O de usuarios; hacerlo en hora punta.
Solución: Programa escaneos de checksum fuera de pico. Hashea solo subconjuntos inmutables o de alto valor. Mantén manifiestos rodantes por partición/día en lugar de escanear todo el árbol.
6) Síntoma: el destino tiene dotfiles extra y archivos de metadatos “raros”
Causa raíz: copia desde macOS (AppleDouble ._), metadatos de Windows o artefactos de software de backup.
Solución: Excluye patrones de basura conocidos intencionalmente, pero documenta las exclusiones. Mejor: separa “datos” de “artefactos del SO cliente” en la fuente.
7) Síntoma: los resultados de la comparación difieren según quién lo ejecuta
Causa raíz: diferencias de permisos afectan lo que find puede ver; algunos archivos son ilegibles para no-root. Además, NFS root-squash puede ocultar realidades de propiedad.
Solución: Ejecuta comparaciones con privilegios consistentes. Para restauraciones a nivel sistema, hazlo como root en ambos extremos (con precaución). Captura errores de find y trátalos como fallos, no como ruido.
8) Síntoma: un archivo con el mismo nombre sobrescribió a otro durante la copia
Causa raíz: sistema de archivos de destino case-insensitive; Readme y README colisionan.
Solución: No copies árboles case-sensitive a volúmenes case-insensitive a menos que tengas una política de nombres y validación. Detecta colisiones normalizando mayúsculas/minúsculas en los manifiestos antes de la migración.
Listas de verificación / plan paso a paso
Checklist A: “Solo necesito saber qué falta” (rápido, bajo riesgo)
- Confirma el alcance: elige los directorios raíz y asegúrate de las barras finales correctas para rsync (
/src/vs/src). - Ejecuta rsync dry-run con comparación itemizada:
cr0x@server:~$ rsync -a --dry-run --itemize-changes /data/src/ /data/dst/ | head -50 sending incremental file list >f+++++++++ reports/2026-01.csv - Si necesitas detectar extras en el destino, añade
--delete(aún dry-run) y revisa las líneas*deleting. - Decide: si el objetivo es espejo, arregla sincronizando; si el objetivo es “backup mantiene más”, no borres.
Checklist B: “Necesito demostrar integridad” (más lento, defendible)
- Estabiliza el dataset: snapshot o pausa escrituras. Si no puedes, sé honesto sobre la incertidumbre.
- Genera un manifiesto SHA-256 ordenado en la fuente:
cr0x@server:~$ cd /data/src cr0x@server:~$ find . -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/src.sha256 cr0x@server:~$ tail -1 /tmp/src.sha256 3d4c... ./reports/2026-01.csv - Copiar el manifiesto al destino (o generarlo allí también) y verificar:
cr0x@server:~$ cd /data/dst cr0x@server:~$ sha256sum -c /tmp/src.sha256 | tail -3 ./images/logo.png: OK ./reports/2026-01.csv: OK - Cualquier
FAILEDo “No such file” es un fallo grave. Resync y re-verifica. - Decide: si los fallos persisten, detente e investiga corrupción de almacenamiento/red, RAM defectuosa, controladoras o una aplicación que modifica archivos post-copia.
Checklist C: “La restauración debe funcionar” (permisos, ACLs y xattrs)
- Elige una muestra representativa de archivos: configs, ejecutables, secretos y directorios que imponen permisos.
- Compara metadatos:
cr0x@server:~$ stat -c '%a %U:%G %n' /data/src/bin/app /data/dst/bin/app 755 root:root /data/src/bin/app 755 root:root /data/dst/bin/app - Si tu entorno usa ACLs/xattrs, revísalas explícitamente (
getfacl,getfattr). - Corrige el método de copia (
rsync -aAX) y vuelve a ejecutar la validación.
Checklist D: “Dataset grande, tiempo limitado” (triage)
- Ejecuta una comparación de manifiestos de rutas+y+tamaños (barata) para encontrar archivos faltantes y con tamaños distintos.
- Hashea solo los archivos con tamaño distinto y una muestra aleatoria de archivos “mismo tamaño”.
- Si la muestra aleatoria falla, amplía el alcance del hashing. Si pasa, procede con confianza cautelosa y documenta lo hecho.
FAQ
1) ¿Cuál es la forma más rápida de comparar dos carpetas en Linux?
Para uso operativo, rsync -a --dry-run --itemize-changes suele ser la comparación accionable más rápida. Lee principalmente metadatos, no el contenido completo, por lo que escala mejor que hashear.
2) ¿Verifica diff -rq el contenido de archivos?
Sí, puede leer y comparar contenidos de archivos, lo que lo hace más definitivo que comparaciones por mtime/tamaño. También puede ser mucho más lento en árboles grandes y ruidoso en datasets con muchos binarios.
3) ¿Cuándo debo usar checksums?
Usa checksums cuando necesites prueba: migraciones donde borrarás la fuente, verificación de cumplimiento, pruebas de restauración o cuando sospeches corrupción. Usa manifiestos y rsync para detección diaria de deriva.
4) ¿Es rsync --checksum lo mismo que un manifiesto de checksums?
No exactamente. --checksum hace que rsync calcule checksums para decidir si transferir. Aún requiere leer todo el contenido de los archivos y no es un artefacto duradero a menos que captures los resultados por separado. Un manifiesto es un registro independiente que puedes volver a comprobar más tarde.
5) ¿Por qué veo cambios cuando nadie tocó los archivos?
Causas comunes: diferencias por redondeo de timestamps, deriva de reloj, actualizaciones de metadatos por antivirus/indexadores, caché de atributos NFS o herramientas que reescriben archivos in-place (aunque el contenido sea lógicamente igual).
6) ¿Cómo comparar carpetas por SSH sin traer todos los datos por la red?
Genera manifiestos pequeños en cada lado (rutas+tamaños, o checksums si hace falta) y compara las salidas de texto. O usa rsync dry-run por SSH, que transfiere solo metadatos y listas de archivos.
7) ¿Y los symlinks y hard links?
Los symlinks pueden compararse como enlaces o como destinos desreferenciados, dependiendo de la herramienta y las banderas. Los hard links requieren manejo especial si quieres preservar relaciones de enlace; de lo contrario las copias pueden duplicar datos y aún “parecer correctas” por contenido.
8) ¿Cómo manejar nombres de archivo con espacios y caracteres raros en manifiestos?
Usa pipelines delimitados por nulos: find ... -print0 con sort -z y xargs -0. Evita el análisis ingenuo por líneas cuando las rutas pueden contener tabs o saltos de línea.
9) ¿Puedo confiar en comparaciones por tamaño de archivo para integridad?
La coincidencia de tamaño es útil para triage rápido y detectar truncamientos obvios, pero no prueba identidad de contenido. Si está en juego mucho, el tamaño es una pista, no evidencia.
10) ¿Cómo comparar solo un subconjunto (excluir caches, temporales, logs)?
Usa exclusiones de rsync (o poda con find) explícita y consistentemente. Mantén la lista de exclusiones bajo control de versiones, porque las “exclusiones temporales” tienden a volverse puntos ciegos permanentes.
Próximos pasos que puedes hacer hoy
- Define un estándar para tu organización: rsync dry-run para comparaciones diarias, manifiestos de checksums para migraciones y verificación de restauraciones.
- Escribe qué significa “igual” para cada flujo: solo existencia, fidelidad de metadatos o identidad por bytes. Ponlo en el runbook para que a las 3 a.m. no improvises.
- Construye un script reutilizable de manifiestos que sea seguro con nulos y ordenado, y guarda los manifiestos junto a backups/snapshots.
- Programa comprobaciones pesadas (hashing de todo el árbol) fuera de pico y mide el impacto con
iostaty cronometraje. No adivines. - Practica la verificación de restauraciones en un subconjunto pequeño pero representativo semanalmente. No por amor al papeleo. Porque los incidentes adoran las sorpresas.
Si te llevas una cosa de todo esto: empieza barato, escala solo cuando la evidencia lo exija y nunca compares un objetivo en movimiento a menos que disfrutes discutir filosofía con tu arreglo de almacenamiento.