Comparar directorios pero no contenido de archivos

21

Con diff -r puedo hacer esta tarea, sin embargo, lleva mucho tiempo porque diff comprueba el contenido del archivo.

Quiero algo que determine que dos archivos son iguales en cuanto a su tamaño, última modificación, etc. Pero no es necesario verificar el archivo poco a poco (por ejemplo, un video lleva muuuucho tiempo)

¿Hay alguna otra manera?

eez0
fuente

Respuestas:

20

rsync, por defecto, compara solo los metadatos del archivo.

rsync -n -a -i --delete source/ target/

explicación:

  • -n en realidad no copie ni elimine <- ¡ESTO ES IMPORTANTE! 1
  • -a compare todos los metadatos del archivo como marca de tiempo y atributos
  • -i imprimir una línea de información por archivo
  • --delete también reporta archivos que no están en la fuente

nota: es importante agregar los nombres de directorio con una barra inclinada. Esto es una cosa rsync.

si también desea ver líneas impresas para archivos que son idénticos, proporcione -idos veces

rsync -n -a -ii --delete source/ target/

salida de ejemplo:

*deleting   removedfile   (file in target but not in source)
.d..t...... ./            (directory with different timestamp)
>f.st...... modifiedfile  (file with different size and timestamp)
>f+++++++++ newfile       (file in source but not in target)
.f          samefile      (file that has same metadata. only with -ii)

recuerde que rsync solo compara metadatos. eso significa que si el contenido del archivo cambió pero los metadatos se mantuvieron igual, rsync informará que el archivo es el mismo. Este es un escenario poco probable. por lo tanto, confíe en que cuando los metadatos son los mismos, los datos son los mismos, o tiene que comparar los datos del archivo poco a poco.

bonificación: para obtener información sobre el progreso, consulte aquí: ¿ Tiempo estimado o trabajo restante para terminar para rsync?

lesmana
fuente
1
¡Los cortes source/y target/también son muy importantes! (Sin ellos, comparará los nombres de los directorios de origen y destino junto con los nombres de los archivos secundarios, por lo que todos los nombres de los archivos serán diferentes)
Peschü
Ojalá hubiera leído tu comentario antes, ¡esto es muy importante! Omití la barra solo en la fuente y luego me preguntaba por qué los archivos en el destino no aparecían *deleting, pero los archivos que están en la fuente solo aparecían. Las barras son fáciles de olvidar accidentalmente y luego obtienes una salida plausible pero incorrecta.
user643011
3

Usar la -q( --briefopción) con diff -r( diff -qr). Desde la infopágina de GNU diff:

1.6 Resumiendo qué archivos difieren

Cuando solo desea averiguar si los archivos son diferentes y no le importan las diferencias, puede usar el formato de salida de resumen. En este formato, en lugar de mostrar las diferencias entre los archivos, la diff' simply reports whether files differ. Theopción --brief '(`-q') selecciona este formato de salida.

Este formato es especialmente útil cuando se comparan los contenidos de dos directorios. También es mucho más rápido que hacer las comparaciones normales de línea por línea, porque 'diff' puede dejar de analizar los archivos tan pronto como sepa que existen diferencias.

Esto no comparará línea por línea, sino más bien el archivo en su conjunto, lo que acelera enormemente el procesador (lo que está buscando).

sombreador
fuente
1
El problema de - q es que compara lo normal y cuando encuentra una diferencia se detiene (si fuera el modo normal, sigue comparando), por lo que si los archivos grandes son iguales durará mucho.
eez0
2

Aquí hay un script rápido de Python que verificará que los nombres de archivo, mtimes y los tamaños de archivo sean todos iguales:

import os
import sys

def getStats(path):
    for pathname, dirnames, filenames in os.walk(path):
        for filename in ( os.path.join(pathname, x) for x in filenames ):
            stat = os.stat(filename)
            yield filename[len(path):], stat.st_mtime, stat.st_size

sys.exit(tuple(getStats(sys.argv[1])) != tuple(getStats(sys.argv[2])))
Chris Down
fuente
1

Si solo necesita saber si los archivos de dos ramas del sistema de archivos son diferentes (sin mirar dentro de los archivos), puede hacer algo como esto:

find /opt/branch1 -type f | sort | xargs -i md5sum {} >/tmp/branch1;
find /opt/branch2 -type f | sort | xargs -i md5sum {} >/tmp/branch2;
diff /tmp/branch1 /tmp/branch2;

HTH

Chaky
fuente
0

Basado en el guión de Chris Down, este guión es un poco más "visual". Llamándola con dos argumentos folder1y folder2, camina la primera carpeta y para cada archivo busca un archivo correspondiente en la segunda carpeta. Si se encuentra, la ruta relativa se imprime en verde, si tienen un tiempo o tamaño modificado diferente, se imprime en amarillo y, si no se encuentra, se imprime en rojo.

#!/usr/bin/env python

import os
import sys
from termcolor import colored

def compare_filestats(file1,file2):
    """
    Compares modified time and size between two files.
    Return:
        -1 if file1 or file2 does not exist
         0 if they exist and compare equal
         1 if they have different modified time, but same size
         2 if they have different size, but same modified time
         3 if they have different size, and different modified time
    """

    if not os.path.exists(file1) or not os.path.exists(file2):
        return -1

    stat1 = os.stat(file1)
    stat2 = os.stat(file2)

    return (stat1.st_mtime != stat2.st_mtime) \
        + 2*(stat1.st_size != stat2.st_size)

def compare_folders(folder1,folder2):
    """
    folder1: serves as reference and will be walked through
    folder2: serves as target and will be querried for each file in folder1

    Prints colored status for each file in folder1:
        missing: file was not found in folder2 
        mtime  : modified time is different
        size   : filesize is different
        ok     : found with same filestats
    """
    for dirpath, dirnames, filenames in os.walk(folder1):
        for file1 in ( os.path.join(dirpath, x) for x in filenames ):
            relpath = file1[len(folder1):]
            file2 = os.path.join( folder2, relpath )
            comp = compare_filestats(file1,file2)

            if comp < 0:
                status = colored('[missing]','red')
            elif comp == 1:
                status = colored('[mtime  ]','yellow')
            elif comp >= 2:
                status = colored('[size   ]','yellow')
            else:
                status = colored('[ok     ]','green')

            print status, relpath

if __name__ == '__main__':
    compare_folders(sys.argv[1],sys.argv[2])

Tenga en cuenta que esto no es suficiente para decidir si las dos carpetas son iguales, deberá ejecutarlo en ambos sentidos para asegurarse. En la práctica, si solo quieres saber si las carpetas son iguales , entonces el script de Chris es mejor. Si desea saber lo que falta o es diferente de una carpeta a otra , entonces mi script le dirá.

NOTA: necesitará instalado termcolor, pip install termcolor.

Sheljohn
fuente
0

Si desea comparar solo una estructura y alguna información básica sobre los archivos, puede probar algo como esto:

diff <(cd $DIR1 && ls -laR) <(cd $DIR2 && ls -laR)

No lo probé, así que cualquier edición es bienvenida :)

Volodymyr
fuente
2
Esto no funcionará ya que los nombres de los directorios también estarán en los resultados.
Chris Down
¿Qué pasa si excluiremos la primera columna con los nombres de directorio? como <(ls -laR | awk '{$ 1 = ""; print}')
Volodymyr
No todas las líneas son nombres de directorio, por lo que no funcionará correctamente.
Chris Down
Aproveche el hecho de que cada uno <()tiene su propio entorno. Editado
un CVn