md5sum 프로그램은 디렉토리에 대한 체크섬을 제공하지 않습니다. 하위 디렉토리의 파일을 포함하여 디렉토리의 전체 내용에 대한 단일 MD5 체크섬을 얻고 싶습니다. 즉, 모든 파일로 구성된 하나의 결합 된 체크섬입니다. 이것을 할 수있는 방법이 있습니까?
md5sum 프로그램은 디렉토리에 대한 체크섬을 제공하지 않습니다. 하위 디렉토리의 파일을 포함하여 디렉토리의 전체 내용에 대한 단일 MD5 체크섬을 얻고 싶습니다. 즉, 모든 파일로 구성된 하나의 결합 된 체크섬입니다. 이것을 할 수있는 방법이 있습니까?
답변:
올바른 방법은 요구하는 이유에 따라 다릅니다.
트리의 파일 내용에 대한 해시가 필요한 경우 다음과 같은 트릭을 수행합니다.
$ find -s somedir -type f -exec md5sum {} \; | md5sum
먼저 모든 파일 내용을 예측 가능한 순서로 개별적으로 요약 한 다음 해당 파일 이름 목록과 MD5 해시를 해시 자체로 전달하여 트리에있는 파일 중 하나의 내용이 변경 될 때만 변경되는 단일 값을 제공합니다.
불행히도 find -s
macOS, 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
프로그램 이 그 대표적인 예 입니다.
이 방법은 md5sum
N + 1 번을 호출하는 다소 비효율적입니다. 여기서 N은 트리의 파일 수이지만 파일 및 디렉토리 메타 데이터 해시를 피하는 데 필요한 비용입니다.
파일 내용뿐만 아니라 트리의 모든 내용이 변경 되었음을 감지해야하는 경우 tar
디렉토리 내용을 압축하여 요청하십시오 md5sum
.
$ tar -cf - somedir | md5sum
tar
파일 권한, 소유권 등도 볼 수 있기 때문에 파일 내용의 변경뿐만 아니라 그에 대한 변경도 감지합니다.
이 방법은 트리를 한 번만 통과하고 해시 프로그램을 한 번만 실행하기 때문에 상당히 빠릅니다.
위의 find
기본 방법 과 마찬가지로 tar
기본 파일 시스템이 반환하는 순서대로 파일 이름을 처리합니다. 응용 프로그램에서 이러한 일이 발생하지 않도록 할 수도 있습니다. 그럴 가능성이있는 세 가지 다른 사용 패턴을 생각할 수 있습니다. (우리는 지정되지 않은 동작 영역에 들어가기 때문에 그것들을 나열하지 않을 것입니다. 각 파일 시스템은 OS의 버전마다 다를 수 있습니다.)
자신이 오 탐지를 얻는다면 Gilles 'answer 의 find | cpio
옵션을 사용하는 것이 좋습니다 .
find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
모든 파일 이름을 무시하려면 (개행과 함께 작동해야 함)
체크섬은 파일을 문자열로 결정적이고 명확하게 표현해야합니다. 결정 론적이란 동일한 위치에 동일한 파일을 배치하면 동일한 결과를 얻을 수 있음을 의미합니다. 명백한 것은 두 개의 서로 다른 파일 세트가 서로 다른 표현을 가지고 있음을 의미합니다.
파일을 포함하는 아카이브를 만드는 것이 좋습니다. 이것은 명백한 표현입니다 (아카이브를 추출하여 파일을 복구 할 수 있기 때문에). 날짜 및 소유권과 같은 파일 메타 데이터를 포함 할 수 있습니다. 그러나 이것은 아직 옳지 않습니다. 아카이브는 파일이 저장된 순서와 압축에 적용 가능한 경우에 따라 다르기 때문에 모호합니다.
해결책은 파일 이름을 아카이브하기 전에 정렬하는 것입니다. 파일 이름에 줄 바꿈이 포함되어 있지 않으면 파일 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()
LC_ALL=C sort
다른 환경에서 확인 하는 것은 어떻습니까 ... (+ 1 btw)
LC_ALL=C
여러 시스템 및 OS에서 실행중인 경우 정렬 순서를 설정해야합니다 .
cpio -o -
뜻입니까? cpio는 기본적으로 stdin / out을 사용하지 않습니까? GNU cpio 2.12 제작cpio: Too many arguments
md5deep 을 보십시오 . 관심을 가질만한 md5deep의 일부 기능 :
재귀 작업-md5deep은 전체 디렉토리 트리를 재귀 적으로 검사 할 수 있습니다. 즉, 디렉토리의 모든 파일 및 모든 서브 디렉토리의 모든 파일에 대해 MD5를 계산하십시오.
비교 모드-md5deep은 알려진 해시 목록을 받아 입력 파일 세트와 비교할 수 있습니다. 프로그램은 알려진 해시 목록과 일치하는 입력 파일 또는 일치하지 않는 입력 파일을 표시 할 수 있습니다.
...
.../foo: Is a directory
.
md5deep -r -l -j0 . | md5sum
( -r
재귀 적 인 곳 은 -l
"상대 경로 사용"을 의미하므로 두 디렉토리의 내용을 비교하려고 할 때 파일의 절대 경로가 방해받지 않으며 -j0
1 스레드를 사용하여 비결 정성 방지 개별 md5sum에 다른 순서로 반환 됨).
목표가 두 디렉토리 사이의 차이점을 찾는 것이라면 diff 사용을 고려하십시오.
이 시도:
diff -qr dir1 dir2
모든 파일을 재귀 적으로 해시 한 다음 결과 텍스트를 해시 할 수 있습니다.
> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-
md5deep 이 필요합니다.
md5deep
사용 hashdeep
하는 대신 .
## Invoked from: /home/myuser/dev/
현재 경로와를 포함한 일부 헤더를 출력 합니다 ## $ hashdeep -s -r -l ~/folder/
. 정렬해야하므로 현재 폴더 또는 명령 줄을 변경하면 최종 해시가 달라집니다.
내용이 다른 디렉토리에 있기 때문에 파일 이름 만 확인한 버전이 필요했습니다.
이 버전 (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는 스크립트.
nix-hash
에서 닉스의 패키지 관리자
nix-hash 명령은 각 경로 내용의 암호화 해시를 계산하여 표준 출력에 인쇄합니다. 기본적으로 MD5 해시를 계산하지만 다른 해시 알고리즘도 사용할 수 있습니다. 해시는 16 진수로 인쇄됩니다.
해시는 각 경로의 직렬화 (경로를 기반으로하는 파일 시스템 트리 덤프)를 통해 계산됩니다. 이를 통해 일반 파일뿐만 아니라 디렉토리 및 심볼릭 링크를 해시 할 수 있습니다. 덤프는 nix-store --dump에서 생성 한 NAR 형식입니다. 따라서 nix-hash 경로는 nix-store --dump path | md5sum.
나는 이것을 적당한 볼륨으로 내 스 니펫을 사용합니다 .
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -
이 XXXL에 대한 하나 :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -
-xdev
플래그는 무엇입니까?
man find
그리고 훌륭한 매뉴얼을 읽으십시오;)
-xdev Don't descend directories on other filesystems.
이 훌륭한 답변에 대한 후속 조치로 , 큰 디렉토리의 체크섬 계산 속도를 높이려면 GNU Parallel을 사용해보십시오 .
find -s somedir -type f | parallel -k -n 100 md5 {} | md5
(이는 Mac을 사용하고 md5
필요에 따라 교체합니다.)
-k
플래그는 그 지시, 중요하다 parallel
, 그렇지 않으면 전체 합이 파일이 모두 같은 경우에도 실행 실행 변경할 수 있습니다, 질서를 유지 할 수 있습니다. 100 개의 인수로 -n 100
각 인스턴스를 실행한다고하면 md5
최상의 런타임을 위해 조정할 수있는 매개 변수입니다. (개인의 경우에는 오류가 발생했지만) -X
플래그 도 참조하십시오 parallel
.
잘 테스트되고 복제본 찾기, 데이터 및 메타 데이터 비교, 추가 및 변경 사항 및 제거 표시를 포함하여 여러 작업을 지원하는 스크립트는 Fingerprint 와 같은 것이 좋습니다.
지문은 현재 디렉토리에 대한 단일 체크섬을 생성하지 않지만 해당 디렉토리에있는 모든 파일에 대한 체크섬을 포함하는 스크립트 파일을 생성합니다.
fingerprint analyze
이것은 index.fingerprint
체크섬, 파일 이름 및 파일 크기를 포함하는 현재 디렉토리에서 생성 됩니다. 기본적으로 MD5
와를 모두 사용합니다 SHA1.256
.
앞으로 Merkle Trees에 대한 지원을 지문에 추가하여 단일 최상위 체크섬을 제공 할 것입니다. 지금은 확인을 위해 해당 파일을 유지해야합니다.
새로운 실행 파일이나 복잡한 솔루션을 원하지 않았으므로 여기에 내 취해야합니다.
#!/bin/sh
# md5dir.sh by Camilo Martin, 2014-10-01.
# Give this a parameter and it will calculate an md5 of the directory's contents.
# It only takes into account file contents and paths relative to the directory's root.
# This means that two dirs with different names and locations can hash equally.
if [[ ! -d "$1" ]]; then
echo "Usage: md5dir.sh <dir_name>"
exit
fi
d="$(tr '\\' / <<< "$1" | tr -s / | sed 's-/$--')"
c=$((${#d} + 35))
find "$d" -type f -exec md5sum {} \; | cut -c 1-33,$c- | sort | md5sum | cut -c 1-32
이것은 내가 머리 위로 가지고있는 것입니다.이 작업을 실제로 한 시간을 보낸 사람은 다른 문제와 모퉁이를 잡을 것입니다.
여기에 도구가 있습니다 (면책 조항 : 나는 그것에 기여합니다) dtreetrawl , 메모리에 매우 가벼워 대부분의 경우를 다루며 가장자리에서 약간 거칠지 만 상당히 도움이되었습니다.
Usage: dtreetrawl [OPTION...] "/trawl/me" [path2,...] Help Options: -h, --help Show help options Application Options: -t, --terse Produce a terse output; parsable. -d, --delim=: Character or string delimiter/separator for terse output(default ':') -l, --max-level=N Do not traverse tree beyond N level(s) --hash Hash the files to produce checksums(default is MD5). -c, --checksum=md5 Valid hashing algorithms: md5, sha1, sha256, sha512. -s, --hash-symlink Include symbolic links' referent name while calculating the root checksum -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
인간 친화적 출력의 예 :
... ... //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
이 답변은 Tar 출력을 사용하여 디렉토리 내용을 해시하는 접근법에 대한 보충 업데이트입니다. 왜냐하면 그것은 얼마 전에 Warren Young 과 Gilles 의 탁월한 답변에서 제안 된 것처럼 디렉토리 내용을 해시합니다 .
그 이후로 최소한 openSUSE (릴리스 12.2 이후)는 기본 GNU Tar 형식을 "GNU tar 1.13.x 형식" 에서 (약간) 우수한 "POSIX 1003.1-2001 (pax) 형식"으로 변경했습니다 . 또한 상류 (GNU 타르의 개발자들 사이에서) 그들은 예를 들어의 마지막 단락 참조 같은 마이그레이션을 수행하는 토론 이 페이지 의 GNU 타르 설명서를 :
GNU tar의 기본 형식은 컴파일 타임에 정의됩니다. 을 실행
tar --help
하고 출력의 마지막 줄을 검사하여 확인할 수 있습니다 . 일반적으로 GNU tar는gnu
형식으로 아카이브를 작성하도록 구성 되지만 이후 버전은로 전환됩니다posix
.
(이 페이지는 GNU Tar에서 사용할 수있는 다양한 아카이브 형식에 대한 좋은 검토도 제공합니다.)
우리의 경우 디렉토리 내용을 tar하고 결과를 해시하고 특별한 조치를 취하지 않으면 GNU에서 POSIX 형식으로 변경하면 다음과 같은 결과가 발생합니다.
동일한 디렉토리 내용에도 불구하고 결과 체크섬은 달라집니다.
동일한 디렉토리 내용에도 불구하고 기본 pax 헤더가 사용되는 경우 결과 체크섬은 실행마다 다릅니다.
후자는 POSIX (pax) 형식 %d/PaxHeaders.%p/%f
이 GNU Tar에서 기본적으로 형식 문자열에 의해 결정되는 확장 된 pax 헤더를 포함한다는 사실에서 비롯됩니다 . 이 문자열 내에서 지정 %p
자는 생성 Tar 프로세스의 프로세스 ID로 대체되며 실행마다 다릅니다. 참조 이 섹션 의 GNU 타르 설명서 특히 이 하나의 세부 사항을.
2019 년 3 월 28 일부터 지금 까지이 문제를 해결하는 업스트림 커밋이 허용됩니다.
따라서 주어진 사용 사례에서 GNU Tar을 계속 사용하려면 다음과 같은 대체 옵션을 권장 할 수 있습니다.
Tar 옵션 --format=gnu
을 사용하여 "old"형식으로 아카이브를 생성하도록 Tar에 명시 적으로 지시 하십시오 . "이전"체크섬을 확인하려면 필수입니다.
최신 POSIX 형식을 사용하되 적절한 pax 헤더를 명시 적으로 지정하십시오 (예 : by) --pax-option="exthdr.name=%d/PaxHeaders/%f"
. 그러나 이로 인해 "이전"체크섬과의 호환성이 손상됩니다.
다음은 메타 데이터를 포함하여 디렉토리 내용의 체크섬을 계산하기 위해 정기적으로 사용하는 Bash 코드 조각입니다.
( export LC_ALL=C
find <paths> ! -type s -print0 |
sort -z |
tar cp --format=gnu --numeric-owner \
--atime-preserve \
--no-recursion --null --files-from - |
md5sum --binary; )
여기서는 <paths>
체크섬으로 덮고 싶은 모든 디렉토리 경로의 공백으로 구분 된 목록으로 대체됩니다. C 로케일, 파일 이름의 널 바이트 분리 및 파일 시스템 독립적 인 파일 순서를 아카이브에 얻기 위해 찾기 및 정렬을 사용하는 목적은 이미 다른 답변에서 충분히 논의되었습니다.
주변 괄호는 LC_ALL
설정을 서브 쉘에서 로컬로 유지합니다 .
또한 소켓 파일이 디렉토리 내용의 일부인 경우 발생하는 Tar의 경고를 피하기 위해 ! -type s
with 표현식 을 사용합니다 find
. GNU Tar은 소켓을 아카이브하지 않습니다. 건너 뛴 소켓에 대한 알림을 받으려면 해당 표현식을 멀리 두십시오.
--numeric-owner
Tar와 함께 사용 하여 파일 소유자가 모두 알려지지 않은 시스템에서도 나중에 체크섬을 확인할 수 있습니다.
--atime-preserve
Tar에 대한 옵션 <paths>
은 읽기 전용 마운트 장치에있는 경우 생략하는 것이 좋습니다 . 그렇지 않으면 액세스 시간 소인 Tar가 복원 할 수없는 각 단일 파일에 대해 경고가 표시됩니다. write enabled의 <paths>
경우이 옵션을 사용하여 해시 디렉토리의 액세스 타임 스탬프를 유지합니다.
Gilles 제안서--no-recursion
에서 이미 사용 된 Tar 옵션 은 Tar이 재귀 적으로 디렉토리로 내려가는 것을 방지하고 정렬 된 출력 에서 공급되는 모든 파일에 대해 파일 단위로 작동하지 않도록합니다 .find
그리고 마지막으로 내가 사용하는 것은 사실이 아닙니다 . md5sum
실제로 사용 sha256sum
합니다.
find .
대신에 사용하는 것이 가장 좋습니다find somedir
. 이 방법으로 찾을 다른 경로 스펙을 제공 할 때 파일 이름이 동일합니다. 이것은 까다로울 수 있습니다 :-)