¿Cómo comparar partes de archivos por hash?

19

Tengo un archivo descargado con éxito y otra descarga fallida (solo los primeros 100 MB de un archivo grande) que sospecho que es el mismo archivo.

Para verificar esto, me gustaría verificar sus hashes, pero como solo tengo una parte del archivo descargado sin éxito, solo quiero hacer el hash de los primeros megabytes más o menos.

¿Cómo hago esto?

El sistema operativo sería Windows, pero tengo Cygwin y MinGW instalados.

pecó
fuente
1
La comparación eficiente de un archivo en una computadora local con otro archivo en una computadora distante es una parte clave de rsync , que compara partes de los archivos con una función hash especial.
David Cary
@DavidCary En mi caso, no tengo acceso de shell a la computadora remota, pero gracias por la pista, leeré la página de manual
pequé el

Respuestas:

56

Crear hashes para comparar archivos tiene sentido si compara un archivo con muchos o cuando compara muchos archivos entre sí.

No tiene sentido comparar dos archivos una sola vez: el esfuerzo para calcular los hashes es al menos tan alto como caminar sobre los archivos y compararlos directamente.

Una herramienta eficiente de comparación de archivos es cmp:

cmp --bytes $((100 * 1024 * 1024)) file1 file2 && echo "File fragments are identical"

También puede combinarlo ddpara comparar partes arbitrarias (no necesariamente desde el principio) de dos archivos, por ejemplo:

cmp \
    <(dd if=file1 bs=100M count=1 skip=1 2>/dev/null) \
    <(dd if=file2 bs=100M count=1 skip=1 2>/dev/null) \
&& echo "File fragments are identical"
Konrad Rudolph
fuente
66
Nota: crear hashes para comparar archivos también tiene sentido si desea evitar leer dos archivos al mismo tiempo.
Kamil Maciorowski
1
@KamilMaciorowski Sí, es cierto. Pero este método generalmente será más rápido que comparar hashes en el caso de pares.
Konrad Rudolph el
8
Esta es la solución para llevar. cmpes 99.99% seguro que ya está instalado si está bashejecutando, y hace el trabajo. De hecho, cmp -n 131072 one.zip two.zip también hará el trabajo. Pocos caracteres para escribir y ejecución más rápida. Calcular un hash no tiene sentido. Requiere que se lea todo el archivo de 100 MB, más una porción de 100 MB del archivo completo, lo cual no tiene sentido. Si son archivos zip y son diferentes, habrá una diferencia dentro de los primeros cientos de bytes. Sin embargo, Readahead ofrece 128k de forma predeterminada, por lo que también puede comparar 128k (el mismo costo que comparar 1 byte).
Damon
19
La --bytesopción solo complica la tarea. Simplemente ejecute cmpsin esta opción y le mostrará el primer byte que difiere entre los archivos. Si todos los bytes son iguales, se mostrará EOFen el archivo más corto. Esto le dará más información que su ejemplo: cuántos bytes son correctos.
pabouk
2
Si tiene GNU cmp(y, creo que casi todo el mundo lo hace), se puede utilizar --ignore-initialy --bytesargumentos en lugar de complicar las cosas con invocaciones de dd.
Christopher Schultz
12

Lo siento, no puedo intentar exactamente eso, pero de esta manera funcionará

dd if=yourfile.zip of=first100mb1.dat bs=100M count=1
dd if=yourotherfile.zip of=first100mb2.dat bs=100M count=1

Esto te dará los primeros 100 megabytes de ambos archivos.

Ahora obtén los hashes:

sha256sum first100mb1.dat && sha256sum first100mb2.dat 

También puedes ejecutarlo directamente:

dd if=yourfile.zip bs=100M count=1 | sha256sum 
dd if=yourotherfile.zip bs=100M count=1 | sha256sum 
davidbaumann
fuente
1
¿Hay alguna manera de canalizar dd de alguna manera en sha256sum sin el archivo intermedio?
pecado el
1
Agregué
8
¿Por qué crear los hashes? Eso es mucho menos eficiente que simplemente comparar los fragmentos de archivo directamente (usando cmp).
Konrad Rudolph el
En su ejemplo de código intermedio, dice first100mb1.dat dos veces. ¿Quiso decir first100mb 2 .dat para el segundo?
doppelgreener
@KonradRudolph, "¿Por qué crear los hashes?" Su solución (usando cmp) es un ganador sin lugar a dudas. Pero esta forma de resolver el problema (usando hashes) también tiene derecho a existir siempre y cuando realmente resuelva el problema (:
VL-80
7

Todo el mundo parece seguir la ruta de Unix / Linux con esto, pero solo se pueden comparar 2 archivos fácilmente con los comandos estándar de Windows:
FC /B file file2

FC está presente en todas las versiones de Windows NT que se hayan creado. Y (si no recuerdo mal) también estaba presente en DOS.
Es un poco lento, pero eso no importa para un uso único.

Tonny
fuente
6

Podrías comparar directamente los archivos, con un programa de diferencias binario / hexadecimal como vbindiff. Compara rápidamente archivos de hasta 4 GB en Linux y Windows.

Se ve más o menos así, solo con la diferencia resaltada en rojo (1B vs 1C):

one                                       
0000 0000: 30 5C 72 A7 1B 6D FB FC  08 00 00 00 00 00 00 00  0\r..m.. ........  
0000 0010: 00 00 00 00                                       ....
0000 0020:
0000 0030:
0000 0040:
0000 0050:
0000 0060:
0000 0070:
0000 0080: 
0000 0090: 
0000 00A0: 

two        
0000 0000: 30 5C 72 A7 1C 6D FB FC  08 00 00 00 00 00 00 00  0\r..m.. ........  
0000 0010: 00 00 00 00                                       ....               
0000 0020: 
0000 0030:
0000 0040:
0000 0050:
0000 0060:
0000 0070:
0000 0080:
0000 0090:                                
0000 00A0:             
┌──────────────────────────────────────────────────────────────────────────────┐
Arrow keys move  F find      RET next difference  ESC quit  T move top        
C ASCII/EBCDIC   E edit file   G goto position      Q quit  B move bottom     
└──────────────────────────────────────────────────────────────────────────────┘ 
Xen2050
fuente
En mi caso, los archivos son archivos zip, por lo que no hay texto significativo allí. Comparar el valor hash debería ser más rápido y menos propenso a errores.
pecado el
2
Si te refieres al texto ASCII, entonces eso es irrelevante. vbindiff(y el de Konrad cmp) compara datos binarios, byte por byte. De hecho, es mucho más probable que los valores experimenten colisiones
Xen2050
* Significaba "De hecho, los valores de HASH son mucho más propensos a experimentar colisiones" en el comentario anterior, se perdió el h!
Xen2050
0

Sé que dice Bash, pero OP también afirma que tienen Windows. Para cualquiera que quiera / requiera una solución de Windows, hay un programa llamado HxD que es un editor hexadecimal que puede comparar dos archivos. Si los archivos son de diferentes tamaños, indicará si las partes disponibles son las mismas. Y si es necesario, es capaz de ejecutar sumas de verificación para lo que esté seleccionado actualmente. Es gratis y se puede descargar desde: el sitio web HxD . No tengo ninguna conexión con los autores, lo he estado usando durante años.

Blerg
fuente
0

cmp le dirá cuándo dos archivos son idénticos hasta la longitud del archivo más pequeño:

$ dd if=/dev/random bs=8192 count=8192 > a
8192+0 records in
8192+0 records out
67108864 bytes transferred in 0.514571 secs (130417197 bytes/sec)
$ cp a b
$ dd if=/dev/random bs=8192 count=8192 >> b 
8192+0 records in
8192+0 records out
67108864 bytes transferred in 0.512228 secs (131013601 bytes/sec)
$ cmp a b
cmp: EOF on a

cmp le dice que la comparación encontró un EOF en el archivo antes de detectar cualquier diferencia entre los dos archivos.

Jim L.
fuente
Buen punto. Si no lo ha visto, esto es lo que pabouk ya comentó sobre la respuesta aceptada.
pecado