Як я можу обчислити контрольну суму md5 каталогу?


133

Мені потрібно обчислити підсумкову контрольну суму md5 для всіх файлів певного типу ( *.pyнаприклад), розміщених під каталогом та всіх підкаталогів.

Який найкращий спосіб зробити це?

Редагувати: Запропоновані рішення дуже приємні, але це не зовсім те, що мені потрібно. Я шукаю рішення отримати єдину підсумкову контрольну суму, яка однозначно визначить каталог у цілому - включаючи вміст усіх його підкаталогів.


Погляньте на це і це для більш детального пояснення.
luvieere

3
Мені це здається суперпопулярним питанням.
Нолдорін

8
Зауважте, що контрольні суми нічого однозначно не ідентифікують.
Хосам Алі

1
Чому у вас є два дерева каталогів, які можуть бути або не бути "тими ж", які ви хочете однозначно ідентифікувати? Чи має значення створення / зміна / доступ до файлу? Чи потрібен контроль над версіями?
jmucchiello

Що в моєму випадку насправді важливо, це схожість вмісту всього дерева каталогів, що означає AFAIK: 1) вміст будь-якого файлу в дереві каталогів не змінено 2) до дерева каталогів не доданий новий файл 3) жодного файлу було видалено
victorz

Відповіді:


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

Команда find перераховує всі файли, які закінчуються у .py. Md5sum обчислюється для кожного файлу .py. awk використовується для вибору md5sums (ігнорування імен файлів, які можуть бути не унікальними). Md5sums сортуються. Потім md5сум цього відсортованого списку повертається.

Я перевірив це, скопіювавши тестовий каталог:

rsync -a ~/pybin/ ~/pybin2/

Я перейменував деякі файли в ~ / pybin2.

find...md5sumКоманда повертає той же результат для обох каталогів.

2bcf49a4d19ef9abd284311108d626f1  -

24
Зверніть увагу, що та сама контрольна сума буде створена, якщо файл буде перейменований. Таким чином, це справді не відповідає "контрольній сумі, яка однозначно ідентифікує каталог як єдине ціле", якщо ви вважаєте макет файлу частиною підпису.
Валентин Мілеа

1
Ви можете трохи змінити командний рядок, щоб встановити кожну контрольну суму файлу з назвою файлу (а ще краще, відносний шлях до файлу від / path / to / dir /), щоб він враховувався під час остаточної контрольної суми.
Майкл Зільберманн

4
@ zim2001: Так, це може бути змінено, але, як я зрозумів проблему (особливо через коментар ОП під питанням), ОП хотів, щоб будь-які два каталоги вважалися рівними, якщо вміст файлів був однаковим, незалежно від імені файлу чи навіть відносний шлях.
unutbu

@unutbu: Я знаю; я реагував на попередню ноту, від Валентина Мілі.
Майкл Зільберманн

@ValentinMilea просто видаліть awk ...частину, якщо ви вважаєте макет частиною підпису.
segfault

166

Створіть файл архіву дьогтю на льоту та трубі, який md5sum:

tar c dir | md5sum

Це створює єдиний md5sum, який повинен бути унікальним для налаштування вашого файлу та підкаталогу. На диску не створюються файли.


25
@CharlesB за допомогою однієї чекової суми ви ніколи не знаєте, який файл відрізняється. Питання стосувалося єдиної чекової суми для каталогу.
Хоукен

17
ls -alR dir | md5sum. Це ще краще, не стискаючи лише прочитане. Він унікальний тим, що вміст містить модний час та розмір файлу;)
Sid

14
@ Daps0l - у моїй команді немає стиснення. Вам потрібно додати zдля gzip або jдля bzip2. Я не зробив жодного.
ire_and_curses

7
Будьте уважні, що це дозволить інтегрувати часову позначку файлів та інших речей в обчислення контрольної суми, а не лише вміст файлів
Michael Zilbermann

10
Це мило, але насправді це не працює. Немає гарантії, що tarвикористання одного і того ж набору файлів двічі або на двох різних комп’ютерах дасть однаковий точний результат.
флетом

46

Пропозиція ire_and_curses щодо використання tar c <dir>має деякі проблеми:

  • tar обробляє записи каталогу в тому порядку, в якому вони зберігаються у файловій системі, і немає можливості змінити цей порядок. Це ефективно дає абсолютно різні результати, якщо у вас є "однаковий" каталог у різних місцях, і я не знаю, як це виправити (tar не може "сортувати" свої вхідні файли у певному порядку).
  • Мені зазвичай цікаво, чи однакові номери групи і власника, не обов'язково, чи однакові рядкові представлення групи / власника. Це відповідає тому, що, наприклад, rsync -a --deleteробить: він синхронізує практично все (мінус xattrs та acls), але він буде синхронізувати власника та групу на основі їх ідентифікатора, а не на рядковому поданні. Отже, якщо ви синхронізували з іншою системою, яка не обов'язково має однакових користувачів / груп, вам слід додати --numeric-ownerпрапор до tar
  • tar буде містити ім'я файлу каталогу, який ви перевіряєте, лише щось, про що слід пам’ятати.

Поки немає виправлення першої проблеми (або якщо ви впевнені, що вона не впливає на вас), я б не використовував такий підхід.

На findоснові рішення , запропоновані вище , не є також недобре , тому що вони включають в себе тільки файли, які не каталоги, що стає проблемою , якщо вас контрольної суми слід мати на увазі порожні каталоги.

Нарешті, більшість запропонованих рішень не сортуються послідовно, оскільки порівняння може бути різним у різних системах.

Це рішення, яке я придумав:

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

Примітки щодо цього рішення:

  • Потрібно LC_ALL=Cзабезпечити надійний порядок сортування по всіх системах
  • Це не відрізняє каталог "name \ nwithanewline" та два каталоги "name" та "withanewline", але шанс виникнення цього видається дуже малоймовірним. Зазвичай це фіксується -print0прапором, findале оскільки тут відбуваються інші речі, я бачу лише рішення, які б ускладнювали команду, тоді це варто.

PS: одна з моїх систем використовує обмежену службову скриньку, findяка не підтримує -execні -print0прапори, а також додає '/' для позначення каталогів, тоді як Findutils не здається, тому для цієї машини мені потрібно запустити:

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

На щастя, у мене немає файлів / каталогів з новими рядками в їхніх назвах, тому це не проблема в цій системі.


1
+1: Дуже цікаво! Ви хочете сказати, що порядок може відрізнятися між різними типами файлової системи або в межах однієї файлової системи?
ire_and_curses

2
і те й інше. це просто залежить від порядку записів у кожному каталозі. Записи каталогів AFAIK (у файловій системі) просто створюються в тому порядку, в якому ви "створюєте файли в каталозі". Простий приклад: $ mkdir a; торкніться а / файл-1; торкніться a / file-2 $ mkdir b; торкніться b / файл-2; touch b / file-1 $ (cd a; tar -c. | md5sum) fb29e7af140aeea5a2647974f7cdec77 - $ (cd b; tar -c. | md5sum) a3a39358158a87059b9f111ccffa1023 -
Dieter_be

15

Якщо ви дбаєте лише про файли, а не про порожні каталоги, це добре працює:

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

10

Для повноти є md5deep (1) ; це не застосовується безпосередньо через вимогу до * .py фільтра, але має спрацьовувати разом із find (1).


Які параметри я б використовував, якби хотів обчислити лише контрольну суму md5 каталогу?
Ярмарок Габріеля

9

Рішення, яке найкраще працювало для мене:

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

Причина, чому це найкраще працювало для мене:

  1. обробляє імена файлів, що містять пробіли
  2. Ігнорує метадані файлової системи
  3. Виявляє, якщо файл було перейменовано

Питання з іншими відповідями:

Метадані файлової системи не ігноруються для:

tar c - "$path" | md5sum

Не обробляє імена файлів, що містять пробіли, і не визначає, чи файл був перейменований:

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

4

Якщо ви хочете, щоб один md5sum охоплював весь каталог, я б зробив щось подібне

cat *.py | md5sum 

1
Для підкаталів використовуйте щось на зразок cat **.py| md5sum
Рамон

3

Перевіряємо всі файли, включаючи вміст та їхні назви файлів

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

Те саме, що вище, але лише файли * .py

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

Ви також можете слідувати посиланнями, якщо хочете

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

Інші параметри, які ви можете розглянути з використанням 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)


2

Технічно потрібно лише бігати ls -lR *.py | md5sum. Якщо ви не переживаєте за те, щоб хтось змінив файли і не торкнувся їх до їх початкових дат і ніколи не змінив розміри файлів, вихідний lsфайл повинен повідомити вам, чи змінився файл. Мій unix-foo слабкий, тому вам може знадобитися ще кілька параметрів командного рядка, щоб отримати час створення та час модифікації для друку. lsтакож підкаже, чи змінилися дозволи на файли (і я впевнений, що є перемикачі, щоб вимкнути це, якщо про це вам все одно).


3
Це може відповідати деяким випадкам використання, але, як правило, ви хочете, щоб контрольна сума відображала лише вміст, а не дати. Наприклад, якби я touchфайл змінив його дату (але не її вміст), я б очікував, що контрольна сума не зміниться.
Тодд Оуен


1

У мене була така ж проблема, тому я придумав цей скрипт, який просто перелічує md5sums файлів у каталозі, і якщо він знайде підкаталог, він знову запускається звідти, щоб це сталося, сценарій повинен бути в змозі пройти через поточний каталог або з підкаталогу, якщо зазначений аргумент передається в $ 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

Я майже впевнений, що цей сценарій не вдасться, якщо назви файлів містять пробіли або лапки. Мені це дратує баш сценаріїв, але те, що я роблю, - це змінити IFS.
localhost

1

Якщо ви хочете по-справжньому незалежно від атрибутів файлової системи та різниць бітових рівнів деяких версій tar, ви можете використовувати cpio:

cpio -i -e theDirname | md5sum

0

Є ще два рішення:

Створити:

du -csxb /path | md5sum > file

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

Перевірка:

du -csxb /path | md5sum -c file

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

0

md5sumдобре працював для мене, але у мене виникли проблеми з sortсортуванням імен файлів. Тому замість цього я сортував за md5sumрезультатами. Мені також потрібно було виключити деякі файли, щоб створити порівнянні результати.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.