[unix] 디렉토리 내용의 MD5 합계를 하나의 합계로 얻으려면 어떻게합니까?

md5sum 프로그램은 디렉토리에 대한 체크섬을 제공하지 않습니다. 하위 디렉토리의 파일을 포함하여 디렉토리의 전체 내용에 대한 단일 MD5 체크섬을 얻고 싶습니다. 즉, 모든 파일로 구성된 하나의 결합 된 체크섬입니다. 이것을 할 수있는 방법이 있습니까?



답변

올바른 방법은 요구하는 이유에 따라 다릅니다.

옵션 1 : 데이터 만 비교

트리의 파일 내용에 대한 해시가 필요한 경우 다음과 같은 트릭을 수행합니다.

$ find -s somedir -type f -exec md5sum {} \; | md5sum

먼저 모든 파일 내용을 예측 가능한 순서로 개별적으로 요약 한 다음 해당 파일 이름 목록과 MD5 해시를 해시 자체로 전달하여 트리에있는 파일 중 하나의 내용이 변경 될 때만 변경되는 단일 값을 제공합니다.

불행히도 find -smacOS, FreeBSD, NetBSD 및 OpenBSD에서 사용되는 BSD find (1)에서만 작동합니다. GNU 또는 SUS find (1)가있는 시스템에서 비슷한 것을 얻으려면 조금 더 추한 것이 필요합니다.

$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum

find -s에 대한 통화로 교체 되었습니다 sort. 이 -k 2비트는 MD5 해시를 건너 뛰도록 지시하므로 필드 2에서 줄 끝까지의 파일 이름 만 계산하여 정렬합니다 sort.

이 버전의 명령에는 약점이 있습니다. 즉, 줄 바꿈이 포함 된 파일 이름이 있으면 여러 줄로 표시되므로 혼동 될 수 있습니다 sort. find -s트리 탐색 및 정렬이 같은 프로그램 내에서 발생하기 때문에 변형, 그 문제를 가지고 있지 않습니다 find.

두 경우 모두 오탐 (false positive)을 피하기 위해 정렬이 필요합니다. 가장 일반적인 Unix / Linux 파일 시스템은 디렉토리 목록을 안정적이고 예측 가능한 순서로 유지하지 않습니다. ls디렉토리 내용을 자동으로 정렬하는 등의 사용을 인식하지 못할 수 있습니다 . find없이 -s또는 sort호출은 파일의 순서는 입력의 변화로 주어진 경우이 명령이 변경된 해시 값을 제공하게되는, 기본 파일 시스템을 반환 어떤 순서로 파일을 인쇄 할 것입니다.

md5sum명령 md5또는 다른 해시 함수로 명령 을 변경해야 할 수도 있습니다 . 다른 해시 함수를 선택하고 시스템에 대한 두 번째 형식의 명령이 필요한 경우 sort그에 따라 명령 을 조정해야 할 수도 있습니다 . 또 다른 함정은 일부 데이터 합산 프로그램이 파일 이름을 전혀 쓰지 않는다는 것입니다. 예를 들어 구 유닉스 sum프로그램 이 그 대표적인 예 입니다.

이 방법은 md5sumN + 1 번을 호출하는 다소 비효율적입니다. 여기서 N은 트리의 파일 수이지만 파일 및 디렉토리 메타 데이터 해시를 피하는 데 필요한 비용입니다.

옵션 2 : 데이터 메타 데이터 비교

파일 내용뿐만 아니라 트리의 모든 내용이 변경 되었음을 감지해야하는 경우 tar디렉토리 내용을 압축하여 요청하십시오 md5sum.

$ tar -cf - somedir | md5sum

tar파일 권한, 소유권 등도 볼 수 있기 때문에 파일 내용의 변경뿐만 아니라 그에 대한 변경도 감지합니다.

이 방법은 트리를 한 번만 통과하고 해시 프로그램을 한 번만 실행하기 때문에 상당히 빠릅니다.

위의 find기본 방법 과 마찬가지로 tar기본 파일 시스템이 반환하는 순서대로 파일 이름을 처리합니다. 응용 프로그램에서 이러한 일이 발생하지 않도록 할 수도 있습니다. 그럴 가능성이있는 세 가지 다른 사용 패턴을 생각할 수 있습니다. (우리는 지정되지 않은 동작 영역에 들어가기 때문에 그것들을 나열하지 않을 것입니다. 각 파일 시스템은 OS의 버전마다 다를 수 있습니다.)

자신이 오 탐지를 얻는다면 Gilles ‘answerfind | cpio옵션을 사용하는 것이 좋습니다 .


답변

체크섬은 파일을 문자열로 결정적이고 명확하게 표현해야합니다. 결정 론적이란 동일한 위치에 동일한 파일을 배치하면 동일한 결과를 얻을 수 있음을 의미합니다. 명백한 것은 두 개의 서로 다른 파일 세트가 서로 다른 표현을 가지고 있음을 의미합니다.

데이터 및 메타 데이터

파일을 포함하는 아카이브를 만드는 것이 좋습니다. 이것은 명백한 표현입니다 (아카이브를 추출하여 파일을 복구 할 수 있기 때문에). 날짜 및 소유권과 같은 파일 메타 데이터를 포함 할 수 있습니다. 그러나 이것은 아직 옳지 않습니다. 아카이브는 파일이 저장된 순서와 압축에 적용 가능한 경우에 따라 다르기 때문에 모호합니다.

해결책은 파일 이름을 아카이브하기 전에 정렬하는 것입니다. 파일 이름에 줄 바꿈이 포함되어 있지 않으면 파일 find | sort을 나열하여 순서대로 아카이브에 추가 할 수 있습니다. 아카이버에게 디렉토리로 돌아 가지 않도록주의하십시오. POSIX pax, GNU tar 및 cpio의 예는 다음과 같습니다 .

find | LC_ALL=C sort | pax -w -d | md5sum
find | LC_ALL=C sort | tar -cf - -T - --no-recursion | md5sum
find | LC_ALL=C sort | cpio -o | md5sum

이름과 내용 만, 최첨단 방식

메타 데이터가 아닌 파일 데이터 만 고려하려는 경우 파일 내용 만 포함하는 아카이브를 만들 수 있지만이를위한 표준 도구는 없습니다. 파일 내용을 포함하는 대신 파일의 해시를 포함시킬 수 있습니다. 파일 이름에 줄 바꿈이없고 일반 파일과 디렉토리 만있는 경우 (심볼릭 링크 나 특수 파일이없는 경우) 매우 쉽지만 몇 가지 사항을주의해야합니다.

{ export LC_ALL=C;
  find -type f -exec wc -c {} \; | sort; echo;
  find -type f -exec md5sum {} + | sort; echo;
  find . -type d | sort; find . -type d | sort | md5sum;
} | md5sum

빈 디렉토리는 보이지 않으므로 체크섬 목록과 함께 디렉토리 목록을 포함합니다. 파일 목록이 정렬되어 있습니다 (Peter.O 덕분에 특정 재현 가능한 로케일로). echo두 부분을 분리합니다 (이것없이 md5sum일반 파일을 전달할 수있는 출력 처럼 보이는 빈 디렉토리를 만들 수 있습니다). 길이 확장 공격 을 피하기 위해 파일 크기 목록도 포함합니다 .

그건 그렇고, MD5는 더 이상 사용되지 않습니다. 사용 가능한 경우 SHA-2 또는 SHA-1 이상을 사용하십시오.

이름의 개행을 지원하는 이름과 데이터

다음은 GNU 도구를 사용하여 파일 이름을 null 바이트로 구분하는 위의 코드 변형입니다. 이렇게하면 파일 이름에 줄 바꾸기가 포함될 수 있습니다. GNU 다이제스트 유틸리티는 출력에서 ​​특수 문자를 인용하므로 모호한 줄 바꿈이 없습니다.

{ export LC_ALL=C;
  du -0ab | sort -z; # file lengths, including directories (with length 0)
  echo | tr '\n' '\000'; # separator
  find -type f -exec sha256sum {} + | sort -z; # file hashes
  echo | tr '\n' '\000'; # separator
  echo "End of hashed data."; # End of input marker
} | sha256sum

보다 강력한 접근법

다음은 파일 계층 구조를 설명하는 해시를 빌드하는 최소한의 테스트를 거친 Python 스크립트입니다. 디렉토리 및 파일 내용을 고려하고 기호 링크 및 기타 파일을 무시하고 파일을 읽을 수 없으면 치명적인 오류를 반환합니다.

#! /usr/bin/env python
import hashlib, hmac, os, stat, sys
## Return the hash of the contents of the specified file, as a hex string
def file_hash(name):
    f = open(name)
    h = hashlib.sha256()
    while True:
        buf = f.read(16384)
        if len(buf) == 0: break
        h.update(buf)
    f.close()
    return h.hexdigest()
## Traverse the specified path and update the hash with a description of its
## name and contents
def traverse(h, path):
    rs = os.lstat(path)
    quoted_name = repr(path)
    if stat.S_ISDIR(rs.st_mode):
        h.update('dir ' + quoted_name + '\n')
        for entry in sorted(os.listdir(path)):
            traverse(h, os.path.join(path, entry))
    elif stat.S_ISREG(rs.st_mode):
        h.update('reg ' + quoted_name + ' ')
        h.update(str(rs.st_size) + ' ')
        h.update(file_hash(path) + '\n')
    else: pass # silently symlinks and other special files
h = hashlib.sha256()
for root in sys.argv[1:]: traverse(h, root)
h.update('end\n')
print h.hexdigest()


답변

md5deep보십시오 . 관심을 가질만한 md5deep의 일부 기능 :

재귀 작업-md5deep은 전체 디렉토리 트리를 재귀 적으로 검사 할 수 있습니다. 즉, 디렉토리의 모든 파일 및 모든 서브 디렉토리의 모든 파일에 대해 MD5를 계산하십시오.

비교 모드-md5deep은 알려진 해시 목록을 받아 입력 파일 세트와 비교할 수 있습니다. 프로그램은 알려진 해시 목록과 일치하는 입력 파일 또는 일치하지 않는 입력 파일을 표시 할 수 있습니다.


답변

목표가 두 디렉토리 사이의 차이점을 찾는 것이라면 diff 사용을 고려하십시오.

이 시도:

diff -qr dir1 dir2


답변

모든 파일을 재귀 적으로 해시 한 다음 결과 텍스트를 해시 할 수 있습니다.

> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-

md5deep 이 필요합니다.


답변

파일 이름을 제외한 파일 내용

내용이 다른 디렉토리에 있기 때문에 파일 이름 만 확인한 버전이 필요했습니다.

이 버전 (Warren Young ‘s answer) 은 많은 도움이되었지만 내 버전의 md5sum파일 이름은 (명령을 실행 한 경로와 관련하여) 파일 이름 을 출력하고 폴더 이름은 다릅니다. 따라서 개별 파일 체크섬이 일치하더라도 최종 체크섬은 ‘티.

이를 해결하기 위해 필자의 경우 find출력 의 각 줄에서 파일 이름을 제거해야했습니다 (을 사용하여 공백으로 구분 된 첫 번째 단어 만 선택하십시오 cut).

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum


답변

해결책 :

$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad

작동 신속 하고 쉽게 다음 솔루션 bash는 스크립트.

문서 참조 : https://pypi.python.org/pypi/checksumdir/1.0.5