¿Cómo obtengo la suma MD5 de los contenidos de un directorio como una suma?

171

El programa md5sum no proporciona sumas de comprobación para directorios. Quiero obtener una sola suma de verificación MD5 para todo el contenido de un directorio, incluidos los archivos en subdirectorios. Es decir, una suma de verificación combinada hecha de todos los archivos. ¿Hay alguna forma de hacer esto?


fuente

Respuestas:

187

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 -ssolo 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 -scon una llamada a sort. El -k 2bit 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 sortel 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 sortllamada. La find -svariante 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 lsy tal, que silenciosamente ordena el contenido del directorio por usted. findsin -so una sortllamada 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 md5sumcomandos md5o 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 sortcomando en consecuencia. Otra trampa es que algunos programas de suma de datos no escriben un nombre de archivo, un buen ejemplo es el antiguo sumprograma de Unix .

Este método es algo ineficiente, llamando a md5sumN + 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 tarempacar el contenido del directorio y envíelo a md5sum:

$ tar -cf - somedir | md5sum

Debido a que tartambié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 findmétodo basado anteriormente, tarva 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 | cpioopción en la respuesta de Gilles .

Warren Young
fuente
77
Creo que es mejor navegar al directorio que se está comparando y usar en find .lugar de find 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 :-)
Abbafei
¿Deberíamos ordenar los archivos también?
CMCDragonkai
@CMCDragonkai: ¿Qué quieres decir? En el primer caso, qué ordenar la lista de nombres de archivo. En el segundo caso, que deliberadamente no lo hacemos porque parte del hecho hincapié en nada en la primera frase es que el orden de los archivos en un directorio ha cambiado, por lo que no quieres para ordenar nada.
Warren Young
@WarrenYoung ¿Puedes explicar un poco más a fondo por qué la opción 2 no siempre es mejor? Parece ser más rápido, más simple y más multiplataforma. ¿En qué caso no debería ser la opción 1?
Robin Winslow
Opción 1 alternativa: find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1ignorar todos los nombres de archivo (debería funcionar con líneas nuevas)
windm
38

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 | sortpara 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 POSIX pax, GNU tar y cpio:

find | LC_ALL=C sort | pax -w -d | md5sum
find | LC_ALL=C sort | tar -cf - -T - --no-recursion | md5sum
find | LC_ALL=C sort | cpio -o | md5sum

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:

{ export LC_ALL=C;
  find -type f -exec wc -c {} \; | sort; echo;
  find -type f -exec md5sum {} + | sort; echo;
  find . -type d | sort; find . -type d | sort | md5sum;
} | md5sum

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). echosepara las dos partes (sin esto, podría crear algunos directorios vacíos cuyo nombre se vea como una md5sumsalida 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.

{ export LC_ALL=C;
  du -0ab | sort -z; # file lengths, including directories (with length 0)
  echo | tr '\n' '\000'; # separator
  find -type f -exec sha256sum {} + | sort -z; # file hashes
  echo | tr '\n' '\000'; # separator
  echo "End of hashed data."; # End of input marker
} | sha256sum

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.

#! /usr/bin/env python
import hashlib, hmac, os, stat, sys
## Return the hash of the contents of the specified file, as a hex string
def file_hash(name):
    f = open(name)
    h = hashlib.sha256()
    while True:
        buf = f.read(16384)
        if len(buf) == 0: break
        h.update(buf)
    f.close()
    return h.hexdigest()
## Traverse the specified path and update the hash with a description of its
## name and contents
def traverse(h, path):
    rs = os.lstat(path)
    quoted_name = repr(path)
    if stat.S_ISDIR(rs.st_mode):
        h.update('dir ' + quoted_name + '\n')
        for entry in sorted(os.listdir(path)):
            traverse(h, os.path.join(path, entry))
    elif stat.S_ISREG(rs.st_mode):
        h.update('reg ' + quoted_name + ' ')
        h.update(str(rs.st_size) + ' ')
        h.update(file_hash(path) + '\n')
    else: pass # silently symlinks and other special files
h = hashlib.sha256()
for root in sys.argv[1:]: traverse(h, root)
h.update('end\n')
print h.hexdigest()
Gilles
fuente
OK, esto funciona, gracias. ¿Pero hay alguna manera de hacerlo sin incluir ningún metadato? En este momento lo necesito solo para el contenido real.
¿Qué tal LC_ALL=C sortpara comprobar desde diferentes entornos ... (+ 1 por cierto)
Peter.O
¿Hiciste un programa completo de Python para esto? ¡Gracias! Esto es realmente más de lo que esperaba. :-) De todos modos, comprobaré estos métodos, así como la nueva opción 1 de Warren.
Buena respuesta. Establecer el orden de clasificación con LC_ALL=Ces esencial si se ejecuta en múltiples máquinas y sistemas operativos.
Davor Cubranic
Que cpio -o -significa ¿Cpio no usa stdin / out por defecto? GNU cpio 2.12 producecpio: Too many arguments
Jan Tojnar
12

Echa un vistazo a md5deep . Algunas de las características de md5deep que pueden interesarle:

Operación recursiva: md5deep puede examinar recursivamente un árbol de directorios completo. Es decir, calcule el MD5 para cada archivo en un directorio y para cada archivo en cada subdirectorio.

Modo de comparación: md5deep puede aceptar una lista de hashes conocidos y compararlos con un conjunto de archivos de entrada. El programa puede mostrar aquellos archivos de entrada que coinciden con la lista de hashes conocidos o aquellos que no coinciden.

...

servidor de fallas
fuente
Bien, pero no puedo hacer que funcione, dice .../foo: Is a directory, ¿qué da?
Camilo Martin
3
Por sí solo, md5deep no resuelve el problema del OP ya que no imprime un md5sum consolidado, solo imprime el md5sum para cada archivo en el directorio. Dicho esto, puede md5sum la salida de md5deep, ¡no exactamente lo que quería el OP, pero está cerca! por ejemplo, para el directorio actual: md5deep -r -l -j0 . | md5sum(donde -res recursivo, -lsignifica "usar rutas relativas" para que la ruta absoluta de los archivos no interfiera al intentar comparar el contenido de dos directorios, y -j0significa usar 1 hilo para evitar el no determinismo debido a md5sums individuales que se devuelven en diferentes órdenes).
Stevie
¿Cómo ignorar algunos archivos / directorios en la ruta?
Sandeepan Nath
9

Si su objetivo es solo encontrar diferencias entre dos directorios, considere usar diff.

Prueba esto:

diff -qr dir1 dir2
Deepak Mittal
fuente
Sí, esto también es útil. Creo que te refieres a dir1 dir2 en ese comando.
1
Por lo general, no uso GUI cuando puedo evitarlos, pero para diferenciar el directorio, kdiff3 es excelente y también funciona en muchas plataformas.
sinelaw
Los archivos diferentes también se informan con este comando.
Serge Stroobandt
7

Puedes hacer hash de cada archivo de forma recursiva y luego hash el texto resultante:

> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-

Se requiere md5deep .

Pavel Vlasov
fuente
1
en lugar de md5deepusarlo hashdeepen ubuntu 16.04 porque el paquete md5deep es solo un muñeco de transición para hashdeep.
palik
1
He intentado hashdeep. No solo genera hashes, sino también algunos encabezados, incluido ## 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.
truf
3

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 md5summuestra 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 findsalida (seleccione solo la primera palabra separada por espacios usando cut):

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum
Nicole
fuente
Es posible que también deba ordenar las sumas de verificación para obtener una lista reproducible.
Eckes
3

solución :

$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad

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

DmitrySemenov
fuente
si no tiene pip, es posible que deba instalarlo con yum -y install python-pip (o dnf / apt-get)
DmitrySemenov
3

nix-hashdel administrador de paquetes de Nix

El comando nix-hash calcula el hash criptográfico del contenido de cada ruta y lo imprime en la salida estándar. Por defecto, calcula un hash MD5, pero también hay otros algoritmos de hash disponibles. El hash está impreso en hexadecimal.

El hash se calcula sobre una serialización de cada ruta: un volcado del árbol del sistema de archivos enraizado en la ruta. Esto permite hash de directorios y enlaces simbólicos, así como archivos regulares. El volcado está en el formato NAR producido por nix-store --dump. Por lo tanto, la ruta nix-hash produce el mismo hash criptográfico que nix-store --dump path | md5sum.

Igor
fuente
2

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 -

poige
fuente
¿Qué hace la -xdevbandera?
czerasz
Le pide que escriba: man findy lea ese excelente manual;)
poige
Buen punto :-). -xdev Don't descend directories on other filesystems.
czerasz
1
Tenga en cuenta que esto ignora los archivos nuevos y vacíos (como si toca un archivo).
RonJohn
Hay muchos casos en los que esto generará el mismo md5sum con una estructura de archivos y directorios completamente diferente. Cambiar el nombre de los archivos y directorios no cambiará eso en absoluto si no cambia el orden de clasificación de los archivos. Por lo tanto, no recomendaría este enfoque.
Hans-Peter Störr
2

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).

Eckes
fuente
2

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 :

find -s somedir -type f | parallel -k -n 100 md5 {} | md5

(Esto está usando una Mac con md5, reemplace según sea necesario).

El -kindicador es importante, que indica parallelmantener el orden, de lo contrario, la suma total puede cambiar de ejecución a ejecución, incluso si los archivos son todos iguales. -n 100dice que para ejecutar cada instancia md5con 100 argumentos, este es un parámetro que puede ajustar para obtener el mejor tiempo de ejecución. Vea también la -Xbandera de parallel(aunque en mi caso personal que causó un error).

shawkinaw
fuente
1

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.

fingerprint analyze

Esto generará index.fingerprinten el directorio actual que incluye sumas de verificación, nombres de archivo y tamaños de archivo. Por defecto usa ambos MD5y SHA1.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.

ioquatix
fuente
1

No quería nuevos ejecutables ni soluciones torpes, así que aquí está mi opinión:

#!/bin/sh
# md5dir.sh by Camilo Martin, 2014-10-01.
# Give this a parameter and it will calculate an md5 of the directory's contents.
# It only takes into account file contents and paths relative to the directory's root.
# This means that two dirs with different names and locations can hash equally.

if [[ ! -d "$1" ]]; then
    echo "Usage: md5dir.sh <dir_name>"
    exit
fi

d="$(tr '\\' / <<< "$1" | tr -s / | sed 's-/$--')"
c=$((${#d} + 35))
find "$d" -type f -exec md5sum {} \; | cut -c 1-33,$c- | sort | md5sum | cut -c 1-32
Camilo Martin
fuente
0

Un enfoque robusto y limpio.

  • Lo primero es lo primero, ¡no acapares la memoria disponible ! Hash un archivo en trozos en lugar de alimentar todo el archivo.
  • Diferentes enfoques para diferentes necesidades / propósitos (todos los siguientes o elija lo que corresponda):
    • Hash solo el nombre de la entrada de todas las entradas en el árbol de directorios
    • Hash el contenido del archivo de todas las entradas (dejando la meta como, número de inodo, ctime, atime, mtime, tamaño, etc., se entiende la idea)
    • Para un enlace simbólico, su contenido es el nombre de referencia. Hash o elige saltarte
    • Seguir o no seguir (nombre resuelto) el enlace simbólico mientras se mezcla el contenido de la entrada
    • Si es un directorio, su contenido son solo entradas de directorio. Mientras atraviesan recursivamente, se convertirán en hash eventualmente, pero ¿deberían los nombres de entrada de directorio de ese nivel ser etiquetados para etiquetar este directorio? Útil en casos de uso en los que se requiere el hash para identificar un cambio rápidamente sin tener que atravesar profundamente el hash. Un ejemplo sería el cambio de nombre de un archivo, pero el resto del contenido sigue siendo el mismo y todos son archivos bastante grandes
    • Maneje bien los archivos grandes (de nuevo, tenga en cuenta la RAM)
    • Maneje árboles de directorios muy profundos (tenga en cuenta los descriptores de archivos abiertos)
    • Manejar nombres de archivo no estándar
    • ¿Cómo proceder con archivos que son enchufes, tuberías / FIFOs, dispositivos de bloque, dispositivos char? ¿Debes hacerlos hash también?
    • No actualice el tiempo de acceso de ninguna entrada mientras atraviesa porque esto será un efecto secundario y contraproducente (¿intuitivo?) Para ciertos casos de uso.

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.

Usage:
  dtreetrawl [OPTION...] "/trawl/me" [path2,...]

Help Options:
  -h, --help                Show help options

Application Options:
  -t, --terse               Produce a terse output; parsable.
  -d, --delim=:             Character or string delimiter/separator for terse output(default ':')
  -l, --max-level=N         Do not traverse tree beyond N level(s)
  --hash                    Hash the files to produce checksums(default is MD5).
  -c, --checksum=md5        Valid hashing algorithms: md5, sha1, sha256, sha512.
  -s, --hash-symlink        Include symbolic links' referent name while calculating the root checksum
  -R, --only-root-hash      Output only the root hash. Blank line if --hash is not set
  -N, --no-name-hash        Exclude path name while calculating the root checksum
  -F, --no-content-hash     Do not hash the contents of the file

Un ejemplo de salida amigable para los humanos:

...
... //clipped
...
/home/lab/linux-4.14-rc8/CREDITS
        Base name                    : CREDITS
        Level                        : 1
        Type                         : regular file
        Referent name                :
        File size                    : 98443 bytes
        I-node number                : 290850
        No. directory entries        : 0
        Permission (octal)           : 0644
        Link count                   : 1
        Ownership                    : UID=0, GID=0
        Preferred I/O block size     : 4096 bytes
        Blocks allocated             : 200
        Last status change           : Tue, 21 Nov 17 21:28:18 +0530
        Last file access             : Thu, 28 Dec 17 00:53:27 +0530
        Last file modification       : Tue, 21 Nov 17 21:28:18 +0530
        Hash                         : 9f0312d130016d103aa5fc9d16a2437e

Stats for /home/lab/linux-4.14-rc8:
        Elapsed time     : 1.305767 s
        Start time       : Sun, 07 Jan 18 03:42:39 +0530
        Root hash        : 434e93111ad6f9335bb4954bc8f4eca4
        Hash type        : md5
        Depth            : 8
        Total,
                size           : 66850916 bytes
                entries        : 12484
                directories    : 763
                regular files  : 11715
                symlinks       : 6
                block devices  : 0
                char devices   : 0
                sockets        : 0
                FIFOs/pipes    : 0
seis-k
fuente
El asesoramiento general siempre es bienvenido, pero las mejores respuestas son específicas y con código, según corresponda. Si tiene experiencia en el uso de la herramienta a la que se refiere, inclúyala.
bu5hman
@ bu5hman ¡Seguro! No me sentía cómodo diciendo (¿regodeándome?) Más sobre lo bien que funciona desde que estoy involucrado en su desarrollo.
seis-k
0

Haciendo individualmente para todos los archivos en cada directorio.

# Calculating
find dir1 | xargs md5sum > dir1.md5
find dir2 | xargs md5sum > dir2.md5
# Comparing (and showing the difference)
paste <(sort -k2 dir1.md5) <(sort -k2 dir2.md5) | awk '$1 != $3'
Leandro Lima
fuente
0

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 :

El formato predeterminado para GNU tar se define en el momento de la compilación. Puede verificarlo ejecutando tar --helpy examinando las últimas líneas de su salida. Por lo general, GNU tar está configurado para crear archivos en gnuformato, sin embargo, la versión futura cambiará a posix.

(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/%fen GNU Tar. Dentro de esta cadena, el especificador %pse 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=gnupara 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:

( export LC_ALL=C
  find <paths> ! -type s -print0 |
  sort -z |
  tar cp --format=gnu --numeric-owner \
         --atime-preserve \
         --no-recursion --null --files-from - |
  md5sum --binary; )

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_ALLconfiguración local en una subshell.

Además, utilizo la expresión ! -type scon findpara 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-ownercon 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-preserveopció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 la findsalida ordenada .

Y finalmente, no es cierto que yo uso md5sum: en realidad lo uso sha256sum.

Jürgen
fuente
-1

Si no necesita md5, puede probar

find . -type f | xargs cksum | cksum
Martin Koubek
fuente
1
La pregunta específicamente pide md5
RalfFriedl