Linux: вычислить один хэш для данной папки и содержимого?
Конечно, должен быть способ сделать это легко!
Я пробовал приложения командной строки Linux, такие как sha1sum
и md5sum
но они, похоже, способны вычислять хэши отдельных файлов и выводить список значений хэша, по одному для каждого файла.
Мне нужно сгенерировать один хеш для всего содержимого папки (не только имена файлов).
Я хотел бы сделать что-то вроде
sha1sum /folder/of/stuff > singlehashvalue
Изменить: чтобы уточнить, мои файлы находятся на нескольких уровнях в дереве каталогов, они не все находятся в одной корневой папке.
Ответы
Ответ 1
Один из возможных способов:
sha1sum path/to/folder/* | sha1sum
Если существует целое дерево каталогов, вам, вероятно, лучше использовать find и xargs. Одна из возможных команд будет
find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum
И, наконец, если вам также необходимо учитывать разрешения и пустые каталоги:
(find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum;
find path/to/folder \( -type f -o -type d \) -print0 | sort -z | \
xargs -0 stat -c '%n %a') \
| sha1sum
Аргументы для stat
заставят его напечатать имя файла с последующими восьмеричными разрешениями. Два поиска будут выполняться один за другим, вызывая удвоение количества операций ввода-вывода на диске: первый найдет все имена файлов и проверит контрольную сумму, второй найдет все имена файлов и каталогов, имя и режим печати. Список "имен файлов и контрольных сумм", за которым следуют "имена и каталоги с разрешениями", будет затем контрольной суммой для меньшей контрольной суммы.
Ответ 2
-
Используйте инструмент обнаружения вторжений файловой системы, такой как aide.
-
хеш тар-тар из каталога:
tar cvf -/path/to/folder | sha1sum
-
Напишите что-нибудь самостоятельно, например, vatine oneliner
find/path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum
Ответ 3
Вы можете сделать tar -c/path/to/folder | sha1sum
tar -c/path/to/folder | sha1sum
Ответ 4
Если вы просто хотите проверить, изменилось ли что-то в папке, я бы рекомендовал следующее:
ls -alR --full-time /folder/of/stuff | sha1sum
Он просто даст вам хэш вывода ls, который содержит папки, подпапки, их файлы, их метку времени, размер и разрешения. Почти все, что вам нужно, чтобы определить, изменилось ли что-то.
Обратите внимание, что эта команда не будет генерировать хэш для каждого файла, но поэтому она должна быть быстрее, чем использование find.
Ответ 5
Если вы просто хотите хешировать содержимое файлов, игнорируя имена файлов, вы можете использовать
cat $FILES | md5sum
Убедитесь, что у вас есть файлы в том же порядке при вычислении хеша:
cat $(echo $FILES | sort) | md5sum
Но вы не можете иметь каталоги в своем списке файлов.
Ответ 6
Для этого существует python script:
http://code.activestate.com/recipes/576973-getting-the-sha-1-or-md5-hash-of-a-directory/
Если вы измените имена файла без изменения их алфавитного порядка, хеш script не обнаружит его. Но если вы измените порядок файлов или содержимое любого файла, запуск script даст вам другой хеш, чем раньше.
Ответ 7
Надежный и чистый подход
- Перво-наперво, не забивайте доступную память ! Хеш файл в кусках, а не кормить весь файл.
- Различные подходы для разных потребностей/целей (все ниже или выберите то, что когда-либо применимо):
- Хэшировать только имя записи всех записей в дереве каталогов
- Хэшируйте содержимое файла всех записей (оставляя метаданные, номер инода, 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.
-j, --json Output as JSON
-d, --delim=: Character or string delimiter/separator for terse output(default ':')
-l, --max-level=N Do not traverse tree beyond N level(s)
--hash Enable hashing(default is MD5).
-c, --checksum=md5 Valid hashing algorithms: md5, sha1, sha256, sha512.
-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
-s, --hash-symlink Include symbolic links' referent name while calculating the root checksum
-e, --hash-dirent Include hash of directory entries while calculating root checksum
Фрагмент дружественного к человеку результата:
...
... //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
Ответ 8
Я бы передал результаты для отдельных файлов через sort
(чтобы исключить простое переупорядочение файлов для изменения хэша) в md5sum
или sha1sum
, в зависимости от того, что вы выберете.
Ответ 9
Еще один инструмент для достижения этой цели:
http://md5deep.sourceforge.net/
Как и звуки: например, md5sum, но также рекурсивные и другие функции.
Ответ 10
Я написал Groovy script, чтобы сделать это:
import java.security.MessageDigest
public static String generateDigest(File file, String digest, int paddedLength){
MessageDigest md = MessageDigest.getInstance(digest)
md.reset()
def files = []
def directories = []
if(file.isDirectory()){
file.eachFileRecurse(){sf ->
if(sf.isFile()){
files.add(sf)
}
else{
directories.add(file.toURI().relativize(sf.toURI()).toString())
}
}
}
else if(file.isFile()){
files.add(file)
}
files.sort({a, b -> return a.getAbsolutePath() <=> b.getAbsolutePath()})
directories.sort()
files.each(){f ->
println file.toURI().relativize(f.toURI()).toString()
f.withInputStream(){is ->
byte[] buffer = new byte[8192]
int read = 0
while((read = is.read(buffer)) > 0){
md.update(buffer, 0, read)
}
}
}
directories.each(){d ->
println d
md.update(d.getBytes())
}
byte[] digestBytes = md.digest()
BigInteger bigInt = new BigInteger(1, digestBytes)
return bigInt.toString(16).padLeft(paddedLength, '0')
}
println "\n${generateDigest(new File(args[0]), 'SHA-256', 64)}"
Вы можете настроить использование, чтобы не печатать каждый файл, изменять дайджест сообщения, вынимать хеширование каталогов и т.д. Я протестировал его против данных теста NIST и работает, как ожидалось. http://www.nsrl.nist.gov/testdata/
gary-macbook:Scripts garypaduana$ groovy dirHash.groovy /Users/garypaduana/.config
.DS_Store
configstore/bower-github.yml
configstore/insight-bower.json
configstore/update-notifier-bower.json
filezilla/filezilla.xml
filezilla/layout.xml
filezilla/lockfile
filezilla/queue.sqlite3
filezilla/recentservers.xml
filezilla/sitemanager.xml
gtk-2.0/gtkfilechooser.ini
a/
configstore/
filezilla/
gtk-2.0/
lftp/
menus/
menus/applications-merged/
79de5e583734ca40ff651a3d9a54d106b52e94f1f8c2cd7133ca3bbddc0c6758
Ответ 11
Попробуйте сделать это в два этапа:
- создать файл с хэшами для всех файлов в папке
- hash этот файл
Так же:
# for FILE in `find /folder/of/stuff -type f | sort`; do sha1sum $FILE >> hashes; done
# sha1sum hashes
Или сделайте все сразу:
# cat `find /folder/of/stuff -type f | sort` | sha1sum
Ответ 12
Вы можете sha1sum
сгенерировать список хеш-значений, а затем sha1sum
этот список снова, это зависит от того, что именно вы хотите выполнить.
Ответ 13
Я должен был проверить весь каталог для изменений файла.
Но с исключением, отметок времени, владельцев каталогов.
Цель состоит в том, чтобы получить одинаковую сумму где угодно, если файлы идентичны.
В том числе размещены на других машинах, независимо от чего-либо, кроме файлов или изменений в них.
md5sum * | md5sum | cut -d' ' -f1
Он генерирует список хэшей по файлам, а затем объединяет эти хэши в один.
Это намного быстрее, чем метод tar.
Для большей конфиденциальности наших хэшей мы можем использовать sha512sum по тому же рецепту.
sha512sum * | sha512sum | cut -d' ' -f1
Хэши также идентичны везде, где используется sha512sum, но нет никакого известного способа изменить это.
Ответ 14
Вот простой, короткий вариант в Python 3, который отлично работает для небольших файлов (например, дерева исходных текстов или чего-то, где каждый файл может легко помещаться в ОЗУ), игнорируя пустые каталоги, основываясь на идеях других решений:
import os, hashlib
def hash_for_directory(path, hashfunc=hashlib.sha1):
filenames = sorted(os.path.join(dp, fn) for dp, _, fns in os.walk(path) for fn in fns)
index = '\n'.join('{}={}'.format(os.path.relpath(fn, path), hashfunc(open(fn, 'rb').read()).hexdigest()) for fn in filenames)
return hashfunc(index.encode('utf-8')).hexdigest()
Это работает так:
- Найти все файлы в каталоге рекурсивно и отсортировать их по имени
- Рассчитать хэш (по умолчанию: SHA-1) каждого файла (считывает весь файл в память)
- Создайте текстовый индекс со строками "filename = hash"
- Кодировать этот индекс обратно в байтовую строку UTF-8 и хэшировать
Вы можете передать другую хеш-функцию в качестве второго параметра, если SHA-1 не ваша чашка чая.
Ответ 15
Если это git-репо и вы хотите игнорировать любые файлы в .gitignore
, вы можете использовать это:
git ls-files <your_directory> | xargs sha256sum | cut -d" " -f1 | sha256sum | cut -d" " -f1
Это хорошо работает для меня.