¿Cómo puedo calcular una suma de comprobación md5 de un directorio?

133

Necesito calcular una suma de comprobación md5 de resumen para todos los archivos de un tipo particular ( *.pypor ejemplo) ubicados bajo un directorio y todos los subdirectorios.

¿Cuál es la mejor manera de hacer eso?

Editar: Las soluciones propuestas son muy buenas, pero esto no es exactamente lo que necesito. Estoy buscando una solución para obtener una suma de comprobación de resumen única que identifique de forma exclusiva el directorio en su conjunto, incluido el contenido de todos sus subdirectorios.

victorz
fuente
Eche un vistazo a esto y esto para obtener una explicación más detallada.
luvieere 01 de
3
Me parece una pregunta de superusuario.
Noldorin el
8
Tenga en cuenta que las sumas de verificación no identifican nada de forma exclusiva .
Hosam Aly el
1
¿Por qué tendría dos árboles de directorio que pueden ser o no "lo mismo" que desea identificar de forma exclusiva? ¿Importa el archivo crear / modificar / tiempo de acceso? ¿Es el control de versiones lo que realmente necesitas?
jmucchiello 01 de
Lo que realmente importa en mi caso es la similitud de todo el contenido del árbol de directorios, lo que significa AFAIK lo siguiente: 1) el contenido de cualquier archivo en el árbol de directorios no se ha cambiado 2) no se agregó ningún archivo nuevo al árbol de directorios 3) ningún archivo fue eliminado
victorz 03 de

Respuestas:

152
find /path/to/dir/ -type f -name "*.py" -exec md5sum {} + | awk '{print $1}' | sort | md5sum

El comando find enumera todos los archivos que terminan en .py. El md5sum se calcula para cada archivo .py. awk se usa para seleccionar md5sums (ignorando los nombres de archivo, que pueden no ser únicos). Los md5sums están ordenados. Se devuelve el md5sum de esta lista ordenada.

He probado esto copiando un directorio de prueba:

rsync -a ~/pybin/ ~/pybin2/

Cambié el nombre de algunos de los archivos en ~ / pybin2.

El find...md5sumcomando devuelve la misma salida para ambos directorios.

2bcf49a4d19ef9abd284311108d626f1  -
unutbu
fuente
24
Tenga en cuenta que se generará la misma suma de comprobación si se cambia el nombre de un archivo. Por lo tanto, esto realmente no se ajusta a una "suma de verificación que identificará de manera única el directorio como un todo" si considera que el diseño del archivo es parte de la firma.
Valentin Milea
1
podría cambiar ligeramente la línea de comando para prefijar cada suma de verificación del archivo con el nombre del archivo (o mejor aún, la ruta relativa del archivo desde / ruta / a / dir /) para que se tenga en cuenta en la suma de verificación final.
Michael Zilbermann
44
@ zim2001: Sí, podría modificarse, pero como entendí el problema (especialmente debido al comentario del OP bajo la pregunta), el OP quería que cualquiera de los dos directorios se considerara igual si el contenido de los archivos fuera idéntico independientemente del nombre del archivo o incluso camino relativo.
unutbu
@unutbu: lo sé; Estaba reaccionando a la nota anterior, de Valentin Milea.
Michael Zilbermann
@ValentinMilea simplemente elimine la awk ...parte si considera que el diseño es parte de la firma.
segfault
166

Cree un archivo de archivo tar sobre la marcha y canalice eso a md5sum:

tar c dir | md5sum

Esto produce un único md5sum que debería ser exclusivo para la configuración de su archivo y sub-directorio. No se crean archivos en el disco.

ire_and_curses
fuente
25
@CharlesB con una sola suma de verificación, nunca se sabe qué archivo es diferente. La pregunta era sobre una suma de verificación única para un directorio.
Hawken
17
ls -alR dir | md5sum. Esto es aún mejor sin compresión, solo una lectura. Es único porque el contenido contiene el tiempo de modificación y el tamaño del archivo;)
Sid
14
@ Daps0l: no hay compresión en mi comando. Debe agregar zpara gzip o jpara bzip2. Yo tampoco lo he hecho.
ire_and_curses
77
Tenga cuidado de que hacer esto integraría la marca de tiempo de los archivos y otras cosas en el cálculo de la suma de comprobación, no solo el contenido de los archivos
Michael Zilbermann
10
Esto es lindo, pero realmente no funciona. No hay garantía de que tarusar el mismo conjunto de archivos dos veces, o en dos computadoras diferentes, produzca el mismo resultado exacto.
fletom
46

La sugerencia de uso de ire_and_curses tar c <dir>tiene algunos problemas:

  • tar procesa las entradas de directorio en el orden en que se almacenan en el sistema de archivos, y no hay forma de cambiar este orden. Esto efectivamente puede producir resultados completamente diferentes si tiene el "mismo" directorio en diferentes lugares, y no sé cómo solucionarlo (tar no puede "ordenar" sus archivos de entrada en un orden particular).
  • Por lo general, me importa si los números groupid y ownerid son iguales, no necesariamente si la representación de cadena de group / owner es la misma. Esto está en línea con lo que hace por ejemplo rsync -a --delete: sincroniza prácticamente todo (menos xattrs y acls), pero sincronizará el propietario y el grupo en función de su ID, no en la representación de cadena. Entonces, si se sincronizó con un sistema diferente que no necesariamente tiene los mismos usuarios / grupos, debe agregar el --numeric-ownerindicador a tar
  • tar incluirá el nombre de archivo del directorio que está comprobando, solo algo a tener en cuenta.

Mientras no haya una solución para el primer problema (o a menos que esté seguro de que no le afecta), no usaría este enfoque.

Las findsoluciones basadas propuestas anteriormente tampoco son buenas porque solo incluyen archivos, no directorios, lo que se convierte en un problema si la suma de comprobación debe tener en cuenta los directorios vacíos.

Finalmente, la mayoría de las soluciones sugeridas no se clasifican de manera consistente, porque la intercalación puede ser diferente entre los sistemas.

Esta es la solución que se me ocurrió:

dir=<mydir>; (find "$dir" -type f -exec md5sum {} +; find "$dir" -type d) | LC_ALL=C sort | md5sum

Notas sobre esta solución:

  • El LC_ALL=Cobjetivo es garantizar un orden de clasificación confiable en todos los sistemas.
  • Esto no diferencia entre un directorio "llamado \ nwithanewline" y dos directorios "named" y "withanewline", pero la posibilidad de que eso ocurra parece muy poco probable. Por lo general, uno soluciona esto con un -print0indicador, findpero dado que hay otras cosas aquí, solo puedo ver soluciones que harían que el comando sea más complicado de lo que vale la pena.

PD: uno de mis sistemas usa un busybox limitado findque no admite -execni -print0marcas, y también agrega '/' para denotar directorios, mientras que findutils find no parece, por lo que para esta máquina necesito ejecutar:

dir=<mydir>; (find "$dir" -type f | while read f; do md5sum "$f"; done; find "$dir" -type d | sed 's#/$##') | LC_ALL=C sort | md5sum

Afortunadamente, no tengo archivos / directorios con nuevas líneas en sus nombres, por lo que este no es un problema en ese sistema.

Dieter_be
fuente
1
+1: ¡Muy interesante! ¿Está diciendo que el orden puede diferir entre los diferentes tipos de sistemas de archivos o dentro del mismo sistema de archivos?
ire_and_curses
2
ambos. solo depende del orden de las entradas del directorio dentro de cada directorio. Las entradas de directorio AFAIK (en el sistema de archivos) se acaban de crear en el orden en que "crea archivos en el directorio". Un ejemplo simple: $ mkdir a; toque a / archivo-1; toque a / archivo-2 $ mkdir b; toque b / archivo-2; toque b / archivo-1 $ (cd a; tar -c. | md5sum) fb29e7af140aeea5a2647974f7cdec77 - $ (cd b; tar -c. | md5sum) a3a39358158a87059b9f111ccffa1023 -
Dieter_be
15

Si solo le interesan los archivos y no los directorios vacíos, esto funciona bien:

find /path -type f | sort -u | xargs cat | md5sum
tesujimath
fuente
10

En aras de la exhaustividad, hay md5deep (1) ; no es directamente aplicable debido al requisito de filtro * .py pero debería funcionar bien junto con find (1).

Michael Shigorin
fuente
¿Qué parámetros usaría si solo quisiera calcular la suma de verificación md5 de un directorio?
Gabriel Fair
9

Una solución que funcionó mejor para mí:

find "$path" -type f -print0 | sort -z | xargs -r0 md5sum | md5sum

Razón por la que funcionó mejor para mí:

  1. maneja nombres de archivos que contienen espacios
  2. Ignora los metadatos del sistema de archivos
  3. Detecta si el archivo ha cambiado de nombre

Problemas con otras respuestas:

Los metadatos del sistema de archivos no se ignoran para:

tar c - "$path" | md5sum

No maneja nombres de archivos que contienen espacios ni detecta si el archivo ha sido renombrado:

find /path -type f | sort -u | xargs cat | md5sum
Tiago Lopo
fuente
4

Si desea un md5sum que abarque todo el directorio, haría algo como

cat *.py | md5sum 
Ramon
fuente
1
Para subdirs use algo como cat **.py| md5sum
Ramon
3

Suma de comprobación de todos los archivos, incluidos el contenido y sus nombres de archivo

grep -ar -e . /your/dir | md5sum | cut -c-32

Igual que el anterior, pero solo incluye archivos * .py

grep -ar -e . --include="*.py" /your/dir | md5sum | cut -c-32

También puedes seguir enlaces simbólicos si quieres

grep -aR -e . /your/dir | md5sum | cut -c-32

Otras opciones que podría considerar usar con grep

-s, --no-messages         suppress error messages
-D, --devices=ACTION      how to handle devices, FIFOs and sockets;
-Z, --null                print 0 byte after FILE name
-U, --binary              do not strip CR characters at EOL (MSDOS/Windows)
moander
fuente
2

GNU encontrar

find /path -type f -name "*.py" -exec md5sum "{}" +;
ghostdog74
fuente
¿Debería ser la última ficha ? ?
Dan Molding el
2

Técnicamente solo necesitas correr ls -lR *.py | md5sum. A menos que le preocupe que alguien modifique los archivos y los devuelva a sus fechas originales y nunca cambie el tamaño de los archivos, la salida de lsdebería decirle si el archivo ha cambiado. Mi unix-foo es débil, por lo que es posible que necesite más parámetros de línea de comandos para obtener el tiempo de creación y el tiempo de modificación para imprimir. lstambién le dirá si los permisos en los archivos han cambiado (y estoy seguro de que hay interruptores para desactivarlo si no le importa).

jmucchiello
fuente
3
Esto puede ajustarse a algunos casos de uso, pero generalmente desearía que la suma de verificación refleje solo el contenido y no las fechas en absoluto. Por ejemplo, si tengo touchun archivo para cambiar su fecha (pero no su contenido), esperaría que la suma de verificación no se modifique.
Todd Owen
2

Utilizando md5deep:

md5deep -r FOLDER | awk '{print $1}' | sort | md5sum

realmente no importa
fuente
1

Tuve el mismo problema, así que se me ocurrió este script que solo enumera los md5sums de los archivos en el directorio y si encuentra un subdirectorio, se ejecuta nuevamente desde allí, para que esto suceda, el script debe poder ejecutarse a través del actual directorio o desde un subdirectorio si dicho argumento se pasa en $ 1

#!/bin/bash

if [ -z "$1" ] ; then

# loop in current dir
ls | while read line; do
  ecriv=`pwd`"/"$line
if [ -f $ecriv ] ; then
    md5sum "$ecriv"
elif [ -d $ecriv ] ; then
    sh myScript "$line" # call this script again
fi

done


else # if a directory is specified in argument $1

ls "$1" | while read line; do
  ecriv=`pwd`"/$1/"$line

if [ -f $ecriv ] ; then
    md5sum "$ecriv"

elif [ -d $ecriv ] ; then
    sh myScript "$line"
fi

done


fi
alan
fuente
Estoy bastante seguro de que este script fallará si los nombres de archivo contienen espacios o comillas. Esto me molesta con las secuencias de comandos bash, pero lo que hago es cambiar el IFS.
localhost
1

Si realmente desea la independencia de los atributos del sistema de archivos y de las diferencias de nivel de bits de algunas versiones de tar, puede usar cpio:

cpio -i -e theDirname | md5sum
peterh - Restablece a Monica
fuente
0

Hay dos soluciones más:

Crear:

du -csxb /path | md5sum > file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum > /tmp/file

Cheque:

du -csxb /path | md5sum -c file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum -c /tmp/file
Mella
fuente
0

md5sumfuncionó bien para mí, pero tuve problemas con la sortclasificación de los nombres de los archivos. Entonces, en su lugar, ordené por md5sumresultado. También necesitaba excluir algunos archivos para crear resultados comparables.

find . -type f -print0 \ | xargs -r0 md5sum \ | grep -v ".env" \ | grep -v "vendor/autoload.php" \ | grep -v "vendor/composer/" \ | sort -d \ | md5sum

MonoMono
fuente