Как получить сумму MD5 содержимого каталога в виде одной суммы?

171

Программа md5sum не предоставляет контрольные суммы для каталогов. Я хочу получить единую контрольную сумму MD5 для всего содержимого каталога, включая файлы в подкаталогах. То есть одна объединенная контрольная сумма, сделанная из всех файлов. Есть ли способ сделать это?


источник

Ответы:

187

Правильный путь зависит от того, почему вы спрашиваете:

Вариант 1. Сравнение только данных

Если вам просто нужен хеш содержимого файла дерева, это поможет:

$ find -s somedir -type f -exec md5sum {} \; | md5sum

Это сначала суммирует все содержимое файла индивидуально, в предсказуемом порядке, затем передает этот список имен файлов и хэшей MD5 для хеширования, давая единственное значение, которое изменяется только при изменении содержимого одного из файлов в дереве.

К сожалению, find -sработает только с BSD find (1), используемым в macOS, FreeBSD, NetBSD и OpenBSD. Чтобы получить что-то сопоставимое в системе с GNU или SUS find (1), вам нужно что-то более уродливое:

$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum

Мы заменили find -sна звонок sort. -k 2Бит говорит это , чтобы пропустить через хэш MD5, поэтому он сортирует только имена файлов, которые находятся в поле 2 через конец-линии, по sortрасчетам «s.

У этой версии команды есть недостаток, заключающийся в том, что она может запутаться, если у вас есть какие-либо имена файлов с символами новой строки в них, потому что она будет выглядеть как несколько строк в sortвызове. find -sВариант не имеет этой проблемы, так как обход дерева и сортировка происходит в течение одной и той же программы, find.

В любом случае сортировка необходима, чтобы избежать ложных срабатываний: наиболее распространенные файловые системы Unix / Linux не поддерживают списки каталогов в стабильном, предсказуемом порядке. Вы можете не осознавать этого, используя lsи тому подобное, которое молча сортирует содержимое каталога для вас. findбез -sили sortвызов собирается распечатать файлы в любом порядке, в котором их возвращает базовая файловая система, что приведет к тому, что эта команда выдаст измененное значение хеш-функции, если порядок файлов, переданных ей как входные, изменится

Возможно, вам придется изменить md5sumкоманды md5или некоторые другие хэш-функции. Если вы выбираете другую хеш-функцию и вам нужна вторая форма команды для вашей системы, вам может потребоваться настроить sortкоманду соответствующим образом. Еще одна ловушка заключается в том, что некоторые программы суммирования данных вообще не записывают имя файла, основным примером является старая sumпрограмма Unix .

Этот метод несколько неэффективен, вызывая md5sumN + 1 раз, где N - количество файлов в дереве, но это необходимая стоимость, чтобы избежать хэширования метаданных файла и каталога.

Вариант 2: сравнить данные и метаданные

Если вам необходимо определить, что изменилось что- либо в дереве, а не только содержимое файла, попросите tarупаковать содержимое каталога для вас, а затем отправьте его по адресу md5sum:

$ tar -cf - somedir | md5sum

Поскольку tarон также определяет права доступа к файлам, владельца и т. Д., Он также обнаруживает изменения этих вещей, а не только изменения содержимого файла.

Этот метод значительно быстрее, так как он делает только один проход по дереву и запускает хэш-программу только один раз.

Как и в случае findописанного выше метода based, tarпроисходит обработка имен файлов в том порядке, в котором их возвращает базовая файловая система. Вполне может быть, что в вашем приложении вы можете быть уверены, что этого не произойдет. Я могу придумать, по крайней мере, три различных модели использования, где это может иметь место. (Я не собираюсь перечислять их, потому что мы попадаем на неопределенную область поведения. Здесь каждая файловая система может отличаться, даже от одной версии ОС к другой.)

Если вы обнаружите, что получаете ложные срабатывания, я бы рекомендовал find | cpioвыбрать вариант ответа Жиля .

Уоррен Янг
источник
7
Я думаю, что лучше всего перейти к каталогу для сравнения и использовать find .вместо find somedir. Таким образом, имена файлов совпадают, когда указываются разные пути; это может быть сложно :-)
Аббафей
Должны ли мы сортировать файлы тоже?
CMCDragonkai
@CMCDragonkai: Что ты имеешь в виду? В первом случае мы бы отсортировать список имен файлов. Во втором случае мы намеренно этого не делаем, потому что часть выделенного чего-либо в первом предложении состоит в том, что порядок файлов в каталоге изменился, поэтому вам не нужно ничего сортировать.
Уоррен Янг
@WarrenYoung Можете ли вы объяснить более подробно, почему вариант 2 не всегда лучше? Вроде бы быстрее, проще и кроссплатформеннее. В каком случае это не должен быть вариант 1?
Робин Уинслоу
Вариант 1 вариант: find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1игнорировать все имена файлов (должен работать с символами новой строки)
windm
38

Контрольная сумма должна иметь детерминированное и однозначное представление файлов в виде строки. Детерминированный означает, что если вы поместите одни и те же файлы в те же места, вы получите тот же результат. Однозначный означает, что два разных набора файлов имеют разные представления.

Данные и метаданные

Создание архива, содержащего файлы, является хорошим началом. Это однозначное представление (очевидно, поскольку вы можете восстановить файлы, распаковав архив). Это может включать метаданные файла, такие как даты и владелец. Однако это еще не совсем правильно: архив неоднозначен, поскольку его представление зависит от порядка, в котором хранятся файлы, и, если применимо, от сжатия.

Решение заключается в сортировке имен файлов перед их архивированием. Если в именах ваших файлов нет новых строк, вы можете запустить find | sortих перечисление и добавить их в архив в указанном порядке. Позаботьтесь, чтобы сообщить архиватору, чтобы он не использовался в каталогах. Вот примеры с POSIX pax, GNU tar и 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

Только названия и содержание, низкотехнологичный способ

Если вы хотите принимать во внимание только данные файла, а не метаданные, вы можете создать архив, содержащий только содержимое файла, но для этого нет стандартных инструментов. Вместо того, чтобы включать содержимое файла, вы можете включить хеш файлов. Если имена файлов не содержат символов новой строки и имеются только обычные файлы и каталоги (без символических ссылок или специальных файлов), это довольно просто, но вам нужно позаботиться о нескольких вещах:

{ 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

Мы добавили список каталогов в дополнение к списку контрольных сумм, так как в противном случае пустые каталоги были бы невидимы. Список файлов отсортирован (в определенной воспроизводимой локали - спасибо Peter.O за напоминание об этом). echoразделяет две части (без этого вы можете сделать несколько пустых каталогов, чье имя будет выглядеть как md5sumвывод, который также может проходить для обычных файлов). Мы также включили список размеров файлов, чтобы избежать атак с расширением длины .

Кстати, MD5 устарела. Если это возможно, рассмотрите возможность использования SHA-2 или хотя бы SHA-1.

Имена и данные, поддерживающие переводы строк в именах

Вот вариант кода выше, который использует инструменты GNU для разделения имен файлов нулевыми байтами. Это позволяет именам файлов содержать символы новой строки. Утилиты дайджеста GNU заключают в кавычки специальные символы, поэтому не будет неоднозначных строк новой строки.

{ 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

Более надежный подход

Вот минимально протестированный скрипт Python, который создает хэш, описывающий иерархию файлов. Он принимает каталоги и содержимое файлов в учетные записи, игнорирует символические ссылки и другие файлы и возвращает фатальную ошибку, если какой-либо файл не может быть прочитан.

#! /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()
жилль
источник
ОК, это работает, спасибо. Но есть ли способ сделать это без включения каких-либо метаданных? Прямо сейчас мне это нужно только для реального содержания.
Как насчет LC_ALL=C sortпроверки из разных сред ... (+ 1, кстати)
Peter.O
Вы сделали целую программу на Python для этого? Спасибо! Это действительно больше, чем я ожидал. :-) В любом случае, я проверю эти методы, а также новый вариант 1 Уоррена.
Хороший ответ. Установка порядка сортировки с помощью LC_ALL=Cимеет важное значение, если работает на нескольких машинах и ОС.
Davor Cubranic
Что cpio -o -значит? Разве cpio не использует stdin / out по умолчанию? Выпускается GNU cpio 2.12cpio: Too many arguments
Ян Тойнар,
12

Посмотрите на md5deep . Некоторые функции md5deep, которые могут вас заинтересовать:

Рекурсивная операция - md5deep может рекурсивно исследовать все дерево каталогов. То есть вычислите MD5 для каждого файла в каталоге и для каждого файла в каждом подкаталоге.

Режим сравнения - md5deep может принять список известных хэшей и сравнить их с набором входных файлов. Программа может отображать либо те входные файлы, которые соответствуют списку известных хэшей, либо те, которые не совпадают.

...

faultyserver
источник
Хорошо, но не могу заставить его работать, он говорит .../foo: Is a directory, что дает?
Камило Мартин
3
Сам по себе md5deep не решает проблему OP, поскольку не печатает консолидированную сумму md5, он просто печатает сумму md5 для каждого файла в каталоге. Тем не менее, вы можете md5sum вывод md5deep - не совсем то, что хотел ОП, но близко! например, для текущего каталога: md5deep -r -l -j0 . | md5sum(где -rявляется рекурсивным, -lозначает «использовать относительные пути», чтобы абсолютный путь к файлам не мешал при попытке сравнить содержимое двух каталогов, и -j0означает использовать 1 поток для предотвращения недетерминированности из-за отдельным md5sums, возвращаемым в разных заказах).
Стиви,
Как игнорировать некоторые файлы / каталоги в пути?
Сандипан Нат
9

Если ваша цель - просто найти различия между двумя каталогами, рассмотрите возможность использования diff.

Попробуй это:

diff -qr dir1 dir2
Дипак Миттал
источник
Да, это также полезно. Я думаю, что вы имели в виду dir1 dir2 в этой команде.
1
Я обычно не использую GUI, когда я могу их избежать, но для различий в каталогах kdiff3 хорош и также работает на многих платформах.
Синелав
Различные файлы также сообщаются с помощью этой команды.
Серж Строобандт
7

Вы можете рекурсивно хешировать каждый файл, а затем хешировать полученный текст:

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

требуется md5deep .

Павел Власов
источник
1
вместо md5deepиспользования hashdeepв Ubuntu 16.04, потому что пакет md5deep - просто переходная пустышка для hashdeep.
Палик
1
Я пробовал Hashdeep. Он выводит не только хэши, но также и некоторые заголовки, включая ## Invoked from: /home/myuser/dev/ваш текущий путь и ## $ hashdeep -s -r -l ~/folder/. Это нужно отсортировать, поэтому окончательный хеш будет другим, если вы измените текущую папку или командную строку.
truf
3

Только содержимое файла , исключая имена файлов

Мне нужна была версия, которая проверяла только имена файлов, потому что содержимое находится в разных каталогах.

Эта версия (ответ Уоррена Янга) очень помогла, но моя версия md5sumвыводит имя файла (относительно пути, из которого я выполнил команду), и имена папок были разными, поэтому, несмотря на совпадение контрольных сумм отдельных файлов, окончательная контрольная сумма не изменилась. «т.

Чтобы исправить это, в моем случае мне просто нужно было удалить имя файла из каждой строки findвывода (выберите только первое слово, разделенное пробелами, используя cut):

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum
Николь
источник
Вам также может понадобиться отсортировать контрольные суммы, чтобы получить воспроизводимый список.
eckes
3

решение :

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

работает быстрее и проще, чем решение сценариев bash.

см. документ: https://pypi.python.org/pypi/checksumdir/1.0.5

DmitrySemenov
источник
если у вас нет pip, вам может потребоваться установить его с помощью yum -y install python-pip (или dnf / apt-get)
DmitrySemenov
3

nix-hashот менеджера пакетов Nix

Команда nix-hash вычисляет криптографический хэш содержимого каждого пути и выводит его на стандартный вывод. По умолчанию он вычисляет хеш MD5, но доступны и другие алгоритмы хеширования. Хеш печатается в шестнадцатеричном формате.

Хеш вычисляется по сериализации каждого пути: дамп дерева файловой системы с корнем в пути. Это позволяет хешировать каталоги и символические ссылки, а также обычные файлы. Дамп в формате NAR, создаваемый nix-store --dump. Таким образом, путь nix-хеша дает тот же криптографический хеш, что и nix-store --dump path | md5sum.

Игорь
источник
2

Я использую этот мой фрагмент для умеренных объемов :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -

и этот для XXXL :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -

poige
источник
Что делает -xdevфлаг?
Чераз
Он призывает вас набрать: man findи прочитать это прекрасное руководство;)
poige
Хорошая точка зрения :-). -xdev Don't descend directories on other filesystems.
czerasz
1
Обратите внимание, что при этом игнорируются новые пустые файлы (например, если вы прикоснулись к файлу).
RonJohn
Во многих случаях это приводит к одной и той же md5sum с совершенно другой структурой файлов и каталогов. Переименование файлов и каталогов не изменит этого вообще, если это не изменит порядок сортировки файлов. Поэтому я бы не рекомендовал такой подход.
Ганс-Петер Стёрр
2

Хорошая контрольная сумма - это идентификатор Git.

К сожалению, нет отдельного инструмента, который мог бы это сделать (по крайней мере, я этого не знаю), но если у вас есть Git под рукой, вы можете просто притвориться, что создаете новый репозиторий и добавляете файлы, которые вы хотите проверить, в индекс.

Это позволяет создавать (воспроизводимый) хэш дерева, который включает только содержимое, имена файлов и некоторые сокращенные режимы файлов (исполняемые).

Экес
источник
2

В продолжение этого превосходного ответа , если вы хотите ускорить вычисление контрольной суммы для большого каталога, попробуйте GNU Parallel :

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

(Это с использованием Mac md5, замените при необходимости.)

Важен -kфлаг, который указывает parallelна поддержание порядка, в противном случае общая сумма может изменить запуск, даже если файлы все одинаковые. -n 100говорит, что для запуска каждого экземпляра md5с 100 аргументами, это параметр, который вы можете настроить для лучшего времени выполнения. Смотрите также -Xфлаг parallel(хотя в моем личном случае это вызвало ошибку.)

shawkinaw
источник
1

Скрипт, который хорошо протестирован и поддерживает ряд операций, включая поиск дубликатов, сравнение данных и метаданных, показ дополнений, а также изменений и удалений, вам может понравиться Fingerprint .

Отпечаток пальца прямо сейчас не производит единственную контрольную сумму для каталога, но файл расшифровки, который включает контрольные суммы для всех файлов в этом каталоге.

fingerprint analyze

Это сгенерирует index.fingerprintв текущем каталоге, который включает контрольные суммы, имена файлов и размеры файлов. По умолчанию он использует оба MD5и SHA1.256.

В будущем я надеюсь добавить в Fingerprint поддержку Merkle Trees, которая даст вам единую контрольную сумму верхнего уровня. Прямо сейчас вам нужно сохранить этот файл для проверки.

ioquatix
источник
1

Я не хотел новых исполняемых файлов или неуклюжих решений, поэтому вот мое мнение:

#!/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
Камило Мартин
источник
0

Надежный и чистый подход

  • Перво-наперво, не забивайте доступную память ! Хеш-файл в кусках, а не кормить весь файл.
  • Различные подходы для разных потребностей / целей (все ниже или выберите то, что когда-либо применимо):
    • Хэшировать только имя записи всех записей в дереве каталогов
    • Хэшируйте содержимое файла всех записей (оставляя метаданные, номер инода, ctime, atime, mtime, размер и т. Д., Вы получите идею)
    • Для символической ссылки ее содержимое является референтным именем. Хэш или выбрать пропустить
    • Следовать или не следовать (разрешенное имя) по символической ссылке при хешировании содержимого записи
    • Если это каталог, его содержимое - это просто записи каталога. При рекурсивном обходе они будут в конечном итоге хешироваться, но следует ли хэшировать имена записей этого уровня, чтобы пометить этот каталог? Полезно в случаях использования, когда требуется хеш-код, чтобы быстро идентифицировать изменение без необходимости глубокого просмотра для хеширования содержимого. Примером может служить изменение имени файла, но остальное содержимое остается неизменным, и все они являются довольно большими файлами
    • Хорошо обрабатывать большие файлы (опять же, обратите внимание на оперативную память)
    • Обработка очень глубоких деревьев каталогов (обратите внимание на дескрипторы открытых файлов)
    • Обрабатывать нестандартные имена файлов
    • Как поступить с файлами, которые являются сокетами, каналами / FIFO, блочными устройствами, символьными устройствами? Должны ли они их хешировать?
    • Не обновляйте время доступа к любой записи при обходе, потому что это будет побочным эффектом и непродуктивным (интуитивно понятным?) Для определенных случаев использования.

Это то, что у меня на голове, любой, кто потратил некоторое время на работу над этим, практически поймал бы другие ошибки и угловые случаи.

Вот инструмент (отказ от ответственности: я помогаю ему) dtreetrawl , очень легкая память, которая решает большинство случаев, может быть немного грубоватой, но очень полезна.

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

Пример дружественного к человеку результата:

...
... //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
шесть-к
источник
Общие советы всегда приветствуются, но лучшие ответы являются конкретными и с кодом, где это уместно. Если у вас есть опыт использования инструмента, на который вы ссылаетесь, включите его.
bu5hman
@ bu5hman Конечно! Мне было не совсем удобно говорить (злорадствовать?) Больше о том, как хорошо это работает, так как я вовлечен в его разработку.
шесть
0

Делаем индивидуально для всех файлов в каждом каталоге.

# 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'
Леандро Лима
источник
0

Миграция в формат архива POSIX влияет на контрольные суммы на основе GNU Tar

Этот ответ призван стать дополнительным обновлением подхода к использованию вывода Tar для хеширования содержимого каталогов, как это было предложено (среди прочего) в превосходных ответах Уоррена Янга и Жиля некоторое время назад.

С тех пор, по крайней мере, openSUSE (начиная с выпуска 12.2) изменил формат GNU Tar по умолчанию с « формата GNU tar 1.13.x» на (немного) улучшенный «формат POSIX 1003.1-2001 (pax)» . Также вверх по течению (среди разработчиков GNU Tar) они обсуждают выполнение той же миграции, см., Например, последний абзац на этой странице руководства GNU Tar :

Формат по умолчанию для GNU tar определяется во время компиляции. Вы можете проверить это, запустив tar --helpи изучив последние строки его вывода. Как правило, GNU tar настроен на создание архивов в gnuформате, однако будущая версия переключится на posix.

(Эта страница также дает хороший обзор различных форматов архивов, доступных в GNU Tar.)

В нашем случае, когда мы сохраняем содержимое каталога и хэшируем результат, без принятия конкретных мер, переход с формата GNU на POSIX имеет следующие последствия:

  • Несмотря на одинаковое содержимое каталога, итоговая контрольная сумма будет отличаться.

  • Несмотря на идентичное содержимое каталога, итоговая контрольная сумма будет отличаться от запуска к запуску, если используются заголовки pax по умолчанию.

Последнее проистекает из того факта, что формат POSIX (pax) включает расширенные заголовки pax, которые определяются строкой формата, которая по умолчанию используется %d/PaxHeaders.%p/%fв GNU Tar. В этой строке спецификатор %pзаменяется идентификатором процесса генерирующего процесса Tar, который, конечно, отличается от запуска к запуску. Смотрите этот раздел в руководстве GNU Tar и , в частности , этот для деталей.

Только что, начиная с 2019-03-28, существует коммит, принятый вверх по течению, который снимает эту проблему.

Итак, чтобы иметь возможность продолжать использовать GNU Tar в данном случае использования, я могу порекомендовать следующие альтернативные варианты:

  • Используйте опцию Tar, --format=gnuчтобы явно указать Tar для создания архива в «старом» формате. Это обязательно для проверки "старых" контрольных сумм.

  • Используйте более новый формат POSIX, но явно укажите подходящий заголовок pax, например, с помощью --pax-option="exthdr.name=%d/PaxHeaders/%f". Однако это нарушает обратную совместимость со «старыми» контрольными суммами.

Вот фрагмент кода Bash, который я использую на регулярной основе для вычисления контрольных сумм содержимого каталога, включая метаданные:

( 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; )

Здесь <paths>заменяется разделенный пробелами список путей всех каталогов, которые я хочу покрыть контрольной суммой. Цель использования языкового стандарта C, разделения имен файлов по нулевому байту и использования поиска и сортировки для получения порядка файлов в архиве, независимого от файловой системы, уже достаточно обсуждалась в других ответах.

Окружающие скобки сохраняют LC_ALLнастройку локально в подоболочке.

Кроме того, я использую выражение ! -type sс, findчтобы избежать предупреждений от Tar, которые появляются, если файлы сокетов являются частью содержимого каталога: GNU Tar не архивирует сокеты. Если вы предпочитаете получать уведомления о пропущенных сокетах, оставьте это выражение в стороне.

Я использую --numeric-ownerс Tar, чтобы иметь возможность проверять контрольные суммы позже даже в системах, где не все владельцы файлов известны.

--atime-preserveВариант для Tar лучше опустить , если какой - либо из <paths>лежишь на смонтированное устройстве только для чтения. В противном случае вы будете предупреждены о каждом отдельном файле, отметка времени доступа которого Tar не смогла восстановить. Для разрешения записи <paths>я использую эту опцию, чтобы сохранить временные метки доступа в хешированных каталогах.

Опция Tar --no-recursion, которая уже использовалась в предложении Gilles , предотвращает рекурсивный спуск Tar в каталоги и вместо этого работает файл за файлом, независимо от того, что он получает из отсортированного findвывода.

И, наконец, это не правда, что я использую md5sum: я на самом деле использую sha256sum.

Jürgen
источник
-1

Если вам не нужен md5, вы можете попробовать

find . -type f | xargs cksum | cksum
Мартин Кобек
источник
1
Вопрос специально задает md5
RalfFriedl