Правильный путь зависит от того, почему вы спрашиваете:
Вариант 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 .
Этот метод несколько неэффективен, вызывая md5sum
N + 1 раз, где N - количество файлов в дереве, но это необходимая стоимость, чтобы избежать хэширования метаданных файла и каталога.
Вариант 2: сравнить данные и метаданные
Если вам необходимо определить, что изменилось что- либо в дереве, а не только содержимое файла, попросите tar
упаковать содержимое каталога для вас, а затем отправьте его по адресу md5sum
:
$ tar -cf - somedir | md5sum
Поскольку tar
он также определяет права доступа к файлам, владельца и т. Д., Он также обнаруживает изменения этих вещей, а не только изменения содержимого файла.
Этот метод значительно быстрее, так как он делает только один проход по дереву и запускает хэш-программу только один раз.
Как и в случае find
описанного выше метода based, tar
происходит обработка имен файлов в том порядке, в котором их возвращает базовая файловая система. Вполне может быть, что в вашем приложении вы можете быть уверены, что этого не произойдет. Я могу придумать, по крайней мере, три различных модели использования, где это может иметь место. (Я не собираюсь перечислять их, потому что мы попадаем на неопределенную область поведения. Здесь каждая файловая система может отличаться, даже от одной версии ОС к другой.)
Если вы обнаружите, что получаете ложные срабатывания, я бы рекомендовал find | cpio
выбрать вариант ответа Жиля .
find .
вместоfind somedir
. Таким образом, имена файлов совпадают, когда указываются разные пути; это может быть сложно :-)find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
игнорировать все имена файлов (должен работать с символами новой строки)Контрольная сумма должна иметь детерминированное и однозначное представление файлов в виде строки. Детерминированный означает, что если вы поместите одни и те же файлы в те же места, вы получите тот же результат. Однозначный означает, что два разных набора файлов имеют разные представления.
Данные и метаданные
Создание архива, содержащего файлы, является хорошим началом. Это однозначное представление (очевидно, поскольку вы можете восстановить файлы, распаковав архив). Это может включать метаданные файла, такие как даты и владелец. Однако это еще не совсем правильно: архив неоднозначен, поскольку его представление зависит от порядка, в котором хранятся файлы, и, если применимо, от сжатия.
Решение заключается в сортировке имен файлов перед их архивированием. Если в именах ваших файлов нет новых строк, вы можете запустить
find | sort
их перечисление и добавить их в архив в указанном порядке. Позаботьтесь, чтобы сообщить архиватору, чтобы он не использовался в каталогах. Вот примеры с POSIXpax
, GNU tar и cpio:Только названия и содержание, низкотехнологичный способ
Если вы хотите принимать во внимание только данные файла, а не метаданные, вы можете создать архив, содержащий только содержимое файла, но для этого нет стандартных инструментов. Вместо того, чтобы включать содержимое файла, вы можете включить хеш файлов. Если имена файлов не содержат символов новой строки и имеются только обычные файлы и каталоги (без символических ссылок или специальных файлов), это довольно просто, но вам нужно позаботиться о нескольких вещах:
Мы добавили список каталогов в дополнение к списку контрольных сумм, так как в противном случае пустые каталоги были бы невидимы. Список файлов отсортирован (в определенной воспроизводимой локали - спасибо Peter.O за напоминание об этом).
echo
разделяет две части (без этого вы можете сделать несколько пустых каталогов, чье имя будет выглядеть какmd5sum
вывод, который также может проходить для обычных файлов). Мы также включили список размеров файлов, чтобы избежать атак с расширением длины .Кстати, MD5 устарела. Если это возможно, рассмотрите возможность использования SHA-2 или хотя бы SHA-1.
Имена и данные, поддерживающие переводы строк в именах
Вот вариант кода выше, который использует инструменты GNU для разделения имен файлов нулевыми байтами. Это позволяет именам файлов содержать символы новой строки. Утилиты дайджеста GNU заключают в кавычки специальные символы, поэтому не будет неоднозначных строк новой строки.
Более надежный подход
Вот минимально протестированный скрипт Python, который создает хэш, описывающий иерархию файлов. Он принимает каталоги и содержимое файлов в учетные записи, игнорирует символические ссылки и другие файлы и возвращает фатальную ошибку, если какой-либо файл не может быть прочитан.
источник
LC_ALL=C sort
проверки из разных сред ... (+ 1, кстати)LC_ALL=C
имеет важное значение, если работает на нескольких машинах и ОС.cpio -o -
значит? Разве cpio не использует stdin / out по умолчанию? Выпускается GNU cpio 2.12cpio: Too many arguments
Посмотрите на md5deep . Некоторые функции md5deep, которые могут вас заинтересовать:
источник
.../foo: Is a directory
, что дает?md5deep -r -l -j0 . | md5sum
(где-r
является рекурсивным,-l
означает «использовать относительные пути», чтобы абсолютный путь к файлам не мешал при попытке сравнить содержимое двух каталогов, и-j0
означает использовать 1 поток для предотвращения недетерминированности из-за отдельным md5sums, возвращаемым в разных заказах).Если ваша цель - просто найти различия между двумя каталогами, рассмотрите возможность использования diff.
Попробуй это:
источник
Вы можете рекурсивно хешировать каждый файл, а затем хешировать полученный текст:
требуется md5deep .
источник
md5deep
использованияhashdeep
в Ubuntu 16.04, потому что пакет md5deep - просто переходная пустышка для hashdeep.## Invoked from: /home/myuser/dev/
ваш текущий путь и## $ hashdeep -s -r -l ~/folder/
. Это нужно отсортировать, поэтому окончательный хеш будет другим, если вы измените текущую папку или командную строку.Только содержимое файла , исключая имена файлов
Мне нужна была версия, которая проверяла только имена файлов, потому что содержимое находится в разных каталогах.
Эта версия (ответ Уоррена Янга) очень помогла, но моя версия
md5sum
выводит имя файла (относительно пути, из которого я выполнил команду), и имена папок были разными, поэтому, несмотря на совпадение контрольных сумм отдельных файлов, окончательная контрольная сумма не изменилась. «т.Чтобы исправить это, в моем случае мне просто нужно было удалить имя файла из каждой строки
find
вывода (выберите только первое слово, разделенное пробелами, используяcut
):источник
решение :
работает быстрее и проще, чем решение сценариев bash.
см. документ: https://pypi.python.org/pypi/checksumdir/1.0.5
источник
nix-hash
от менеджера пакетов Nixисточник
Я использую этот мой фрагмент для умеренных объемов :
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 -
источник
-xdev
флаг?man find
и прочитать это прекрасное руководство;)-xdev Don't descend directories on other filesystems.
Хорошая контрольная сумма - это идентификатор Git.
К сожалению, нет отдельного инструмента, который мог бы это сделать (по крайней мере, я этого не знаю), но если у вас есть Git под рукой, вы можете просто притвориться, что создаете новый репозиторий и добавляете файлы, которые вы хотите проверить, в индекс.
Это позволяет создавать (воспроизводимый) хэш дерева, который включает только содержимое, имена файлов и некоторые сокращенные режимы файлов (исполняемые).
источник
В продолжение этого превосходного ответа , если вы хотите ускорить вычисление контрольной суммы для большого каталога, попробуйте GNU Parallel :
(Это с использованием Mac
md5
, замените при необходимости.)Важен
-k
флаг, который указываетparallel
на поддержание порядка, в противном случае общая сумма может изменить запуск, даже если файлы все одинаковые.-n 100
говорит, что для запуска каждого экземпляраmd5
с 100 аргументами, это параметр, который вы можете настроить для лучшего времени выполнения. Смотрите также-X
флагparallel
(хотя в моем личном случае это вызвало ошибку.)источник
Скрипт, который хорошо протестирован и поддерживает ряд операций, включая поиск дубликатов, сравнение данных и метаданных, показ дополнений, а также изменений и удалений, вам может понравиться Fingerprint .
Отпечаток пальца прямо сейчас не производит единственную контрольную сумму для каталога, но файл расшифровки, который включает контрольные суммы для всех файлов в этом каталоге.
Это сгенерирует
index.fingerprint
в текущем каталоге, который включает контрольные суммы, имена файлов и размеры файлов. По умолчанию он использует обаMD5
иSHA1.256
.В будущем я надеюсь добавить в Fingerprint поддержку Merkle Trees, которая даст вам единую контрольную сумму верхнего уровня. Прямо сейчас вам нужно сохранить этот файл для проверки.
источник
Я не хотел новых исполняемых файлов или неуклюжих решений, поэтому вот мое мнение:
источник
Надежный и чистый подход
Это то, что у меня на голове, любой, кто потратил некоторое время на работу над этим, практически поймал бы другие ошибки и угловые случаи.
Вот инструмент (отказ от ответственности: я помогаю ему) dtreetrawl , очень легкая память, которая решает большинство случаев, может быть немного грубоватой, но очень полезна.
Пример дружественного к человеку результата:
источник
Делаем индивидуально для всех файлов в каждом каталоге.
источник
Миграция в формат архива 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.)
В нашем случае, когда мы сохраняем содержимое каталога и хэшируем результат, без принятия конкретных мер, переход с формата 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, который я использую на регулярной основе для вычисления контрольных сумм содержимого каталога, включая метаданные:
Здесь
<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
.источник
Если вам не нужен md5, вы можете попробовать
источник