Я пишу скрипт оболочки, который использует его shasum
для проверки того, изменилось ли содержимое каталога.
В Linux и FreeBSD они shasum
ведут себя одинаково shasum <directory>
, однако в MacOS они shasum
выдают мне хешитолько для файлов.
FreeBSD
$ shasum CONTENTS/
7f986e5e5289c59db1bba48df92ffe4707830aaa CONTENTS/
Линукс
$ shasum CONTENTS/
7f986e5e5289c59db1bba48df92ffe4707830aaa CONTENTS/
MacOS
$ shasum CONTENTS/
shasum: CONTENTS/:
Как вычислить хеш каталога в MacOS?
ПОПЫТКА 1: Использование TAR с трубами
Попробовал использовать, но, похоже, эта опция tar не работает на MacOS.
tar cO CONTENTS/ | shasum
tar: Option -O is not permitted in mode -c
da39a3ee5e6b4b0d3255bfef95601890afd80709 -
ПОПЫТКА 2: Использование FIND/EXEC
Это было одинаково для MacOS и FreeBSD, но Linux вернул странный хеш
find CONTENTS -type f -exec shasum {} \; | sort -k 2 | shasum
Линукс
c2ddb9bc5f543e956f5cdcc76750cb78cc5f26f3
FreeBSD
3ac2a9d4e2fc5d2d2ec3c7f612e680990cc35824
MacOS
3ac2a9d4e2fc5d2d2ec3c7f612e680990cc35824
ДРУГИЕ ВЫВОДЫ ПО TAR
tar
было бы отлично, так как он «архивирует» папку, и тогда я мог бы shasum
это сделать, однако порядок того, как tar
«обходить» структуру папок,не согласованы между операционными системами. Как некоторые помощники отметили в комментариях, мне следует использовать одну и ту же версию tar
во всех системах.
Просто пример: в системе 1 у меня такой порядок:
drwxr-xr-x 0 root wheel 0 27 Jul 07:23 usr/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/f0/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/aaa
а в системе 2 у меня следующий порядок:
drwxr-xr-x 0 root wheel 0 27 Jul 07:23 usr/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/aaa
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/aaa
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/f0/aaa
С tar
точки зрения все хорошо, но из-за порядка получается shasum
другой хеш.
ЗАКЛЮЧЕНИЕ
shasum
Linux и BSD единообразны в плане проверки хеша отдельного файла, но когда дело доходит до каталогов, единообразие наблюдается только в MacOS и FreeBSD, возможно, из-за способа сортировки файлов.
Если сортировка выполняется принудительно с помощью find
команды, согласованность достигается только в FreeBSD и MacOS, однако этот метод требует больших временных затрат, поскольку требуется значительное время для вычисления хэшей для каждого отдельного файла, а затем и хэша всей структуры.
Использование tar
для создания временного файла и последующее выполнение shasum
также оказалось несовместимым между Linux и BSD, возможно, из-за разницы в методе архивирования.
Я думаю, что единственный путь вперед — этоперепроектировать мое решение.
решение1
mtree
именно тот инструмент, который вам нужен.
Предполагать:
$ mkdir foo
$ date > foo/date1; sleep 3
$ date > foo/date2; sleep 3
$ date > foo/date3
$ grep . foo/*
foo/date1:Wed Jul 24 16:11:32 PDT 2019
foo/date2:Wed Jul 24 16:11:35 PDT 2019
foo/date3:Wed Jul 24 16:11:38 PDT 2019
$ find . -ls
7318841 0 drwxr-xr-x 3 admin staff 102 Jul 24 16:11 .
7318847 0 drwxr-xr-x 5 admin staff 170 Jul 24 16:11 ./foo
7318849 8 -rw-r--r-- 1 admin staff 29 Jul 24 16:11 ./foo/date1
7318851 8 -rw-r--r-- 1 admin staff 29 Jul 24 16:11 ./foo/date2
7318853 8 -rw-r--r-- 1 admin staff 29 Jul 24 16:11 ./foo/date3
Создайте ссылочный манифест каталога foo
и сохраните его в foo.mtree
:
$ mtree -c -K sha256digest -p foo > foo.mtree
Теперь идите и поработайте с любым файлом в этом каталоге.
$ touch foo/date3
Запустите его mtree
снова и передайте ему созданный ранее манифест, и mtree
он сообщит вам, что изменилось:
$ mtree -p foo < foo.mtree || echo fail
date3 changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
fail
$ echo '$ date > foo/date2' >> bar
$ mtree -p foo < foo.mtree || echo fail
date2 changed
modification time expected Wed Jul 24 16:11:35 2019 found Wed Jul 24 16:19:40 2019
SHA-256 expected c76a568f08d98c2830f2fdfb42415c3ec15341b8741450d4bbd863f1d5c4c691 found ddcf8d07785bfe4d031a989339835dc3b8b44653019568dcee612c44fc8e2f70
date3 changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
fail
Также будет сообщено о любых файлах, отсутствующих foo
или добавленных с момента создания манифеста:
$ mv foo/date1 foo/date4
$ mtree -p foo < foo.mtree || echo fail
. changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:21:38 2019
date2 changed
modification time expected Wed Jul 24 16:11:35 2019 found Wed Jul 24 16:19:40 2019
SHA-256 expected c76a568f08d98c2830f2fdfb42415c3ec15341b8741450d4bbd863f1d5c4c691 found ddcf8d07785bfe4d031a989339835dc3b8b44653019568dcee612c44fc8e2f70
date3 changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
date4 extra
./date1 missing
fail
решение2
Рмлинтсделаю то, что (я так думаю) ты хочешь.
Соответствующие пункты:
- По умолчанию SHA не используется, но его можно использовать.
- Его можно установить на MacOS с помощью homebrew.
- По умолчанию он не вычисляет контрольную сумму для одного указанного каталога. Его можно заставить вычислять контрольные суммы для всех каталогов с заданной начальной точки, как способ поиска «дубликатов» каталогов ниже этой точки. Но в качестве побочного эффекта он также будет делать именно то, о чем вы, кажется, просите.
- Это может оказаться излишним для того, что вы ищете, и вам может потребоваться некоторое время, чтобы определить наилучшие флаги опций для использования, но это довольно надежно.
- Выяснение того, какие флаги использовать, может быть сложным. Получить контрольные суммы каталогов достаточно просто, но заставить егонетделать другие вещи, может быть сложно. (Хотя, если быть точным, он на самом деле ничего не изменяет. В лучшем случае он генерирует скрипт оболочки, который вы можете вручную запустить позже, чтобы изменить что-то, если это необходимо. Похоже, вам нужны выходные файлы JSON и/или CSV, которые дадут вам контрольную сумму каталога, которую вы ищете.)
Я использую rmlint в скрипте bash для поиска дубликатов каталогов. Вот команда, которая сделает минимально то, что вам нужно, и как можно меньше других:
rmlint "base/dir/to/start/from" --see-symlinks --hidden --algorithm=sha256 --types=none,duplicatedirs --no-backup -o csv:log.csv