La forma correcta depende exactamente de por qué estás preguntando:
Opción 1: comparar solo datos
Si solo necesita un hash del contenido del archivo del árbol, esto hará el truco:
$ find -s somedir -type f -exec md5sum {} \; | md5sum
Esto primero resume todo el contenido del archivo individualmente, en un orden predecible, luego pasa esa lista de nombres de archivo y hash MD5 para que se mezclen, dando un valor único que solo cambia cuando cambia el contenido de uno de los archivos en el árbol.
Desafortunadamente, find -s
solo funciona con BSD find (1), utilizado en macOS, FreeBSD, NetBSD y OpenBSD. Para obtener algo comparable en un sistema con GNU o SUS find (1), necesita algo un poco más feo:
$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum
Hemos reemplazado find -s
con una llamada a sort
. El -k 2
bit le dice que omita el hash MD5, por lo que solo clasifica los nombres de archivo, que están en el campo 2 hasta el final de la línea, según sort
el cálculo.
Hay una debilidad con esta versión del comando, que es probable que se confunda si tiene nombres de archivo con nuevas líneas en ellos, porque parecerá que hay varias líneas en la sort
llamada. La find -s
variante no tiene ese problema, porque el recorrido y la clasificación del árbol ocurren dentro del mismo programa find
,.
En cualquier caso, la clasificación es necesaria para evitar falsos positivos: los sistemas de archivos Unix / Linux más comunes no mantienen las listas de directorios en un orden estable y predecible. Es posible que no se dé cuenta de esto al usar ls
y tal, que silenciosamente ordena el contenido del directorio por usted. find
sin -s
o una sort
llamada imprimirá los archivos en cualquier orden que el sistema de archivos subyacente los devuelva, lo que hará que este comando dé un valor hash modificado si el orden de los archivos que se le da como entrada cambia.
Es posible que deba cambiar los md5sum
comandos md5
o alguna otra función hash. Si elige otra función hash y necesita la segunda forma del comando para su sistema, es posible que deba ajustar el sort
comando en consecuencia. Otra trampa es que algunos programas de suma de datos no escriben un nombre de archivo, un buen ejemplo es el antiguo sum
programa de Unix .
Este método es algo ineficiente, llamando a md5sum
N + 1 veces, donde N es el número de archivos en el árbol, pero ese es un costo necesario para evitar el hash de metadatos de archivos y directorios.
Opción 2: Comparar datos y metadatos
Si necesita poder detectar que algo en un árbol ha cambiado, no solo el contenido del archivo, solicite tar
empacar el contenido del directorio y envíelo a md5sum
:
$ tar -cf - somedir | md5sum
Debido a que tar
también ve permisos de archivos, propiedad, etc., esto también detectará cambios en esas cosas, no solo cambios en el contenido del archivo.
Este método es considerablemente más rápido, ya que solo hace una pasada sobre el árbol y ejecuta el programa hash solo una vez.
Al igual que con el find
método basado anteriormente, tar
va a procesar los nombres de los archivos en el orden en que los devuelve el sistema de archivos subyacente. Bien puede ser que en su aplicación, puede estar seguro de que no hará que esto suceda. Puedo pensar en al menos tres patrones de uso diferentes donde es probable que ese sea el caso. (No voy a enumerarlos, porque estamos entrando en un territorio de comportamiento no especificado. Cada sistema de archivos puede ser diferente aquí, incluso de una versión del sistema operativo a la siguiente).
Si te encuentras con falsos positivos, te recomiendo ir con la find | cpio
opción en la respuesta de Gilles .
find .
lugar defind somedir
. De esta forma, los nombres de los archivos son los mismos cuando se proporcionan diferentes especificaciones de ruta para buscar; esto puede ser complicado :-)find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
ignorar todos los nombres de archivo (debería funcionar con líneas nuevas)La suma de comprobación debe ser de una representación determinista e inequívoca de los archivos como una cadena. Determinista significa que si coloca los mismos archivos en las mismas ubicaciones, obtendrá el mismo resultado. No ambiguo significa que dos conjuntos diferentes de archivos tienen representaciones diferentes.
Datos y metadatos.
Hacer un archivo que contenga los archivos es un buen comienzo. Esta es una representación inequívoca (obviamente, ya que puede recuperar los archivos extrayendo el archivo). Puede incluir metadatos de archivo como fechas y propiedad. Sin embargo, esto todavía no es del todo correcto: un archivo es ambiguo, porque su representación depende del orden en que se almacenan los archivos y, si corresponde, de la compresión.
Una solución es ordenar los nombres de los archivos antes de archivarlos. Si los nombres de sus archivos no contienen nuevas líneas, puede ejecutar
find | sort
para enumerarlos y agregarlos al archivo en este orden. Tenga cuidado de decirle al archivero que no vuelva a aparecer en los directorios. Aquí hay ejemplos con POSIXpax
, GNU tar y cpio:Solo nombres y contenidos, la forma de baja tecnología
Si solo desea tener en cuenta los datos del archivo y no los metadatos, puede crear un archivo que incluya solo el contenido del archivo, pero no hay herramientas estándar para eso. En lugar de incluir el contenido del archivo, puede incluir el hash de los archivos. Si los nombres de archivo no contienen líneas nuevas, y solo hay archivos y directorios regulares (sin enlaces simbólicos o archivos especiales), esto es bastante fácil, pero debe ocuparse de algunas cosas:
Incluimos una lista de directorios además de la lista de sumas de verificación, ya que de lo contrario los directorios vacíos serían invisibles. La lista de archivos está ordenada (en un entorno local específico y reproducible, gracias a Peter.O por recordarme eso).
echo
separa las dos partes (sin esto, podría crear algunos directorios vacíos cuyo nombre se vea como unamd5sum
salida que también podría pasar a archivos normales). También incluimos una lista de tamaños de archivo, para evitar ataques de extensión de longitud .Por cierto, MD5 está en desuso. Si está disponible, considere usar SHA-2, o al menos SHA-1.
Nombres y datos, apoyando nuevas líneas en nombres
Aquí hay una variante del código anterior que se basa en herramientas GNU para separar los nombres de archivo con bytes nulos. Esto permite que los nombres de archivo contengan nuevas líneas. Las utilidades de resumen de GNU citan caracteres especiales en su salida, por lo que no habrá nuevas líneas ambiguas.
Un enfoque más robusto.
Aquí hay un script Python mínimamente probado que crea un hash que describe una jerarquía de archivos. Toma los directorios y el contenido de los archivos en las cuentas e ignora los enlaces simbólicos y otros archivos, y devuelve un error fatal si algún archivo no se puede leer.
fuente
LC_ALL=C sort
para comprobar desde diferentes entornos ... (+ 1 por cierto)LC_ALL=C
es esencial si se ejecuta en múltiples máquinas y sistemas operativos.cpio -o -
significa ¿Cpio no usa stdin / out por defecto? GNU cpio 2.12 producecpio: Too many arguments
Echa un vistazo a md5deep . Algunas de las características de md5deep que pueden interesarle:
fuente
.../foo: Is a directory
, ¿qué da?md5deep -r -l -j0 . | md5sum
(donde-r
es recursivo,-l
significa "usar rutas relativas" para que la ruta absoluta de los archivos no interfiera al intentar comparar el contenido de dos directorios, y-j0
significa usar 1 hilo para evitar el no determinismo debido a md5sums individuales que se devuelven en diferentes órdenes).Si su objetivo es solo encontrar diferencias entre dos directorios, considere usar diff.
Prueba esto:
fuente
Puedes hacer hash de cada archivo de forma recursiva y luego hash el texto resultante:
Se requiere md5deep .
fuente
md5deep
usarlohashdeep
en ubuntu 16.04 porque el paquete md5deep es solo un muñeco de transición para hashdeep.## Invoked from: /home/myuser/dev/
cuál es su ruta actual y## $ hashdeep -s -r -l ~/folder/
. Esto tiene que clasificarse, por lo que el hash final será diferente si cambia su carpeta o línea de comando actual.Contenido del archivo solamente , excluyendo nombres de archivo
Necesitaba una versión que solo verificara los nombres de los archivos porque los contenidos residen en diferentes directorios.
Esta versión (la respuesta de Warren Young) ayudó mucho, pero mi versión
md5sum
muestra el nombre de archivo (en relación con la ruta desde la que ejecuté el comando), y los nombres de las carpetas eran diferentes, por lo tanto, aunque las sumas de verificación de archivos individuales coincidían, la suma de verificación final no 't.Para solucionarlo, en mi caso, solo necesitaba quitar el nombre de archivo de cada línea de la
find
salida (seleccione solo la primera palabra separada por espacios usandocut
):fuente
solución :
funciona una solución rápida y más fácil que bash scripting.
ver documento: https://pypi.python.org/pypi/checksumdir/1.0.5
fuente
nix-hash
del administrador de paquetes de Nixfuente
Utilizo este mi fragmento para volúmenes moderados :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -
y este para XXXL :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -
fuente
-xdev
bandera?man find
y lea ese excelente manual;)-xdev Don't descend directories on other filesystems.
Una buena suma de comprobación de árbol es el id de árbol de Git.
Desafortunadamente, no hay una herramienta independiente disponible que pueda hacer eso (al menos no lo sé), pero si tiene Git a mano, puede pretender configurar un nuevo repositorio y agregar los archivos que desea verificar al índice.
Esto le permite producir el hash de árbol (reproducible), que incluye solo contenido, nombres de archivo y algunos modos de archivo reducidos (ejecutables).
fuente
Como seguimiento de esta excelente respuesta , si desea acelerar el cálculo de la suma de comprobación para un directorio grande, pruebe GNU Parallel :
(Esto está usando una Mac con
md5
, reemplace según sea necesario).El
-k
indicador es importante, que indicaparallel
mantener el orden, de lo contrario, la suma total puede cambiar de ejecución a ejecución, incluso si los archivos son todos iguales.-n 100
dice que para ejecutar cada instanciamd5
con 100 argumentos, este es un parámetro que puede ajustar para obtener el mejor tiempo de ejecución. Vea también la-X
bandera deparallel
(aunque en mi caso personal que causó un error).fuente
Un script que está bien probado y admite una serie de operaciones que incluyen encontrar duplicados, hacer comparaciones tanto en datos como en metadatos, que muestran adiciones, así como cambios y eliminaciones, es posible que le guste Fingerprint .
La huella digital en este momento no produce una sola suma de verificación para un directorio, sino un archivo de transcripción que incluye sumas de verificación para todos los archivos en ese directorio.
Esto generará
index.fingerprint
en el directorio actual que incluye sumas de verificación, nombres de archivo y tamaños de archivo. Por defecto usa ambosMD5
ySHA1.256
.En el futuro, espero agregar soporte para Merkle Trees en Fingerprint, que le dará una suma de control de nivel superior. En este momento, debe conservar ese archivo para realizar la verificación.
fuente
No quería nuevos ejecutables ni soluciones torpes, así que aquí está mi opinión:
fuente
Un enfoque robusto y limpio.
Esto es lo que tengo en la cabeza, cualquiera que haya pasado algún tiempo trabajando en esto prácticamente habría captado otras trampas y casos de esquina.
Aquí hay una herramienta (descargo de responsabilidad: soy un colaborador) dtreetrawl , muy ligero en memoria, que aborda la mayoría de los casos, puede ser un poco difícil, pero ha sido bastante útil.
Un ejemplo de salida amigable para los humanos:
fuente
Haciendo individualmente para todos los archivos en cada directorio.
fuente
La migración al formato de archivo POSIX afecta las sumas de verificación basadas en GNU Tar
Esta respuesta está destinada a ser una actualización complementaria al enfoque de usar la salida Tar para analizar el contenido de los directorios, como se propuso (entre otras cosas) en las excelentes respuestas de Warren Young y Gilles hace algún tiempo.
Desde entonces, al menos openSUSE (desde su lanzamiento 12.2) cambió su formato predeterminado de GNU Tar de " formato GNU tar 1.13.x" al " ligeramente superior " formato POSIX 1003.1-2001 (pax) " . También aguas arriba (entre los desarrolladores de GNU Tar) discuten para realizar la misma migración, ver por ejemplo el último párrafo en esta página del manual GNU Tar :
(Esta página también ofrece una buena revisión de los diferentes formatos de archivo disponibles con GNU Tar).
En nuestro caso, donde alquilamos el contenido del directorio y analizamos el resultado, y sin tomar medidas específicas, un cambio de formato GNU a POSIX tiene las siguientes consecuencias:
A pesar del contenido idéntico del directorio, la suma de comprobación resultante será diferente.
A pesar del contenido idéntico del directorio, la suma de comprobación resultante será diferente de una ejecución a otra si se utilizan los encabezados pax predeterminados.
Esto último proviene del hecho de que el formato POSIX (pax) incluye encabezados de pax extendidos que están determinados por una cadena de formato predeterminada
%d/PaxHeaders.%p/%f
en GNU Tar. Dentro de esta cadena, el especificador%p
se reemplaza por el ID de proceso del proceso Tar generador, que por supuesto es diferente de una ejecución a otra. Consulte esta sección del manual de GNU Tar y, en particular, esta para más detalles.En este momento, que data del 28/03/2019, hay un compromiso aceptado aguas arriba que desactiva este problema.
Entonces, para poder seguir usando GNU Tar en el caso de uso dado, puedo recomendar las siguientes opciones alternativas:
Use la opción Tar
--format=gnu
para indicarle explícitamente a Tar que genere el archivo en el formato "antiguo". Esto es obligatorio para validar sumas de verificación "antiguas".Utilice el formato POSIX más reciente, pero especifique explícitamente un encabezado pax adecuado, por ejemplo, por
--pax-option="exthdr.name=%d/PaxHeaders/%f"
. Sin embargo, esto rompe la compatibilidad con versiones anteriores de las sumas de verificación "antiguas".Aquí hay un fragmento de código Bash que utilizo regularmente para calcular sumas de verificación del contenido del directorio, incluidos los metadatos:
Aquí,
<paths>
se reemplaza por una lista separada por espacios de las rutas de todos los directorios que quiero cubrir con la suma de verificación. El propósito de usar la configuración regional C, la separación de bytes nulos de los nombres de archivo y de buscar y ordenar para obtener un orden independiente del sistema de archivos de los archivos en el archivo ya se discute suficientemente en otras respuestas.Los paréntesis circundantes mantienen la
LC_ALL
configuración local en una subshell.Además, utilizo la expresión
! -type s
confind
para evitar advertencias de Tar que se producen si los archivos de socket son parte del contenido del directorio: GNU Tar no archiva sockets. Si prefiere recibir notificaciones sobre los sockets omitidos, deje esa expresión de lado.Utilizo
--numeric-owner
con Tar, para poder verificar las sumas de verificación más tarde, incluso en los sistemas, donde no se conocen todos los propietarios de archivos.La
--atime-preserve
opción para Tar se omite mejor si alguna de las<paths>
mentiras en un dispositivo montado de solo lectura. De lo contrario, se le advertirá por cada archivo cuya marca de tiempo de acceso Tar no haya podido restaurar. Para escritura habilitada<paths>
, utilizo esta opción, bueno, para preservar las marcas de tiempo de acceso en los directorios hash.La opción Tar
--no-recursion
, que ya se usaba en la propuesta de Gilles , evita que Tar descienda recursivamente a directorios por sí mismo y, en su lugar, opere archivo por archivo en lo que se alimenta de lafind
salida ordenada .Y finalmente, no es cierto que yo uso
md5sum
: en realidad lo usosha256sum
.fuente
Si no necesita md5, puede probar
fuente