Хотя это может звучать как задача, которую можно выполнить с помощью rsync
, ] diff
и тому подобное, мне не удалось добиться успеха.
AFAIK, эти инструменты учитывают структуру каталогов при сравнении файлов.
Таким образом, если «Файл A» находится в ~ / Dir-A
, в то время как «Файл B» находится в ~ / Dir-B / Dir-BB
, они будут обнаружены как разные файлы, даже если у них одинаковый хэш.
Требования / подробности:
Dir-A
и Dir-B
; Dir- A
и НЕ в Dir-B
(и наоборот, желательно в разных списках / результатах); Dir-A
и Dir-B
имеют очень разные структуры. В некоторых случаях предполагается, что Dir-A
будет иметь все, что есть в Dir-B
, а также многое другое; Dir-A
все из нескольких других каталогов. Подводя итог: моя конкретная ситуация включает проверку нескольких резервных копий и копий с очень разным содержанием и структурой.
В некоторых конкретных случаях мне нужно сравнить большую папку (которая является полной резервной копией) с другими меньшими папками, чтобы проверить, есть ли в резервной копии все, что должно быть.
Большое спасибо за внимание.
На самом деле я не понимаю, как это сделать без сценариев, поэтому вот короткий сценарий на Python для начала.
import hashlib
import os
def get_md5_file(filename, chunk_size=10240):
''' Returns md5 sum of the given filename
'''
md5_hash = hashlib.md5()
with open(filename, 'rb') as f:
while True:
data = f.read(chunk_size)
if not data:
break
md5_hash.update(data)
digest = md5_hash.hexdigest()
return digest
#print(get_md5('Dir-A/file1.txt'))
#print(get_md5('Dir-B/Dir-B/file1-duplicate.txt'))
def get_md5_dir(root, result=None):
''' Returns a dictionary with the md5 sum of every filename in directory root
'''
if result is None:
result = dict()
for root, dirs, files in os.walk(root):
for filename in files:
filename = os.path.join(root, filename)
md5 = get_md5_file(filename)
if md5 in result:
print('Warning, duplicate md5 sum', result[md5], filename)
result[md5] = filename
return result
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Compare directories by md5 sum')
parser.add_argument('dirA', help='Specify first directory')
parser.add_argument('dirB', help='Specify one or more directory to compare to',
nargs='+')
args = parser.parse_args()
# Get md5 sum for each file in dirA and each file in (possibly multiple) dirB
md5_dirA = get_md5_dir(args.dirA)
md5_dirB = dict()
for root in args.dirB:
get_md5_dir(root, md5_dirB) # update dict in place
#print(md5_dirA)
#print(md5_dirB)
# print files in dirA, but not in dirB
for md5 in md5_dirA:
if md5 not in md5_dirB:
print('%s (%s) not in dirB' % (md5_dirA[md5], md5))
# print files in dirB, not in dirA
for md5 in md5_dirB:
if md5 not in md5_dirA:
print('%s (%s) not in dirA' % (md5_dirB[md5], md5))
Для использования сохраните как текстовый файл compare_files_by_hash. py, тогда python3 compare_files_by_hash.py Dir-A Dir-B
.
Бонус: если возможно, было бы неплохо иметь возможность проверить, есть ли в Dir-A все из нескольких других каталогов.
Я не уверен, что понял это, но вышеупомянутое позволяет использовать несколько каталогов Dir-B, т.е. вы можете сделать python3 compare_files_by_hash.py Dir-A Dir-B Dir-B-2 Dir-B-3
и будет так, как если бы Dir-B Dir-B-2 Dir-B-3
все были в Dir-B
.