Linux : 주어진 폴더 및 콘텐츠에 대해 단일 해시를 계산합니까?


98

확실히 이것을 쉽게 할 수있는 방법이있을 것입니다!

나는 리눅스 명령 줄과 같은 애플 리케이션 해봤 sha1sum하고 md5sum있지만 개별 파일 및 출력 해시 값 목록, 각 파일에 대해 하나의 해시를 계산 할 수있을 것 같다.

파일 이름뿐만 아니라 폴더의 전체 내용에 대해 단일 해시를 생성해야합니다.

나는 다음과 같은 것을하고 싶다.

sha1sum /folder/of/stuff > singlehashvalue

편집 : 명확히하기 위해 내 파일은 디렉토리 트리의 여러 수준에 있으며 모두 동일한 루트 폴더에 있지 않습니다.


1
'전체 내용'이란 디렉토리에있는 모든 파일의 논리 데이터 또는 루트 해시에 도달하는 동안 메타와 함께 데이터를 의미합니까? 사용 사례의 선택 기준이 매우 광범위하기 때문에 제 답변에서 실용적인 기준을 거의 다루지 않았습니다.
six-k

답변:


124

한 가지 가능한 방법은 다음과 같습니다.

sha1sum 경로 / 대상 / 폴더 / * | sha1sum

전체 디렉토리 트리가있는 경우 find 및 xargs를 사용하는 것이 좋습니다. 가능한 명령 중 하나는

경로 / 대상 / 폴더 찾기 -type f -print0 | 정렬 -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는 파일 이름과 그 뒤에 8 진수 권한을 인쇄하도록합니다. 두 개의 발견은 차례로 실행되어 디스크 IO의 양을 두 배로 늘리고 첫 번째는 모든 파일 이름을 찾고 내용을 체크섬하고 두 번째는 모든 파일 및 디렉토리 이름을 찾고 이름과 모드를 인쇄합니다. "파일 이름 및 체크섬"목록과 그 뒤에 "권한이있는 이름 및 디렉토리"목록이 더 작은 체크섬에 대해 체크섬됩니다.


2
LC_ALL = POSIX를 설정하는 것을 잊지 마십시오. 다양한 도구가 로케일 독립적 인 출력을 생성합니다.
David Schmitt

2
나는 고양이를 찾았다 | sha1sum이 sha1sum보다 상당히 빠름 | sha1sum. YMMV, 시스템에서 다음 각각을 시도하십시오. time find path / to / folder -type f -print0 | 정렬 -z | xargs -0 sha1sum | sha1sum; time find path / to / folder -type f -print0 | 정렬 -z | xargs -0 고양이 | sha1sum
Bruno Bronosky 2011

5
@RichardBronosky-A와 B라는 두 개의 파일이 있다고 가정하겠습니다. A에는 "foo"가 포함되고 B에는 "bar was here"가 포함됩니다. 당신의 방법으로, 우리는 두 파일 C와 D로부터 그것을 분리 할 수 ​​없을 것입니다. 여기서 C는 "foobar"를 포함하고 D는 "was here"를 포함합니다. 각 파일을 개별적으로 해시 한 다음 모든 "파일 이름 해시"쌍을 해시하면 차이점을 확인할 수 있습니다.
Vatine

2
디렉토리 경로에 관계없이이 작업을 수행하려면 (즉, 서로 다른 두 폴더의 해시를 비교하려는 경우) 상대 경로를 사용하고 경로가 최종 해시에 포함되기 때문에 적절한 디렉토리로 변경해야합니다.find ./folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum
robbles

3
@robbles 맞습니다 . 이니셜 /path/to/folder비트 에 넣지 않은 이유 입니다.
Vatine 2013

25
  • aide 와 같은 파일 시스템 침입 탐지 도구를 사용하십시오 .

  • 디렉토리의 타르 볼을 해시합니다.

    tar cvf - /path/to/folder | sha1sum

  • vatine의 oneliner 와 같이 직접 코딩하십시오 .

    find /path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum


3
tar 솔루션의 경우 +1. 이것이 가장 빠르지 만 v. verbosity를 낮추면 속도가 느려질뿐입니다.
Bruno Bronosky 2013

7
tar 솔루션은 파일을 비교할 때 동일한 순서로 가정합니다. 비교를 수행 할 때 파일이 상주하는 파일 시스템에 따라 달라집니다.
nos

5
git 해시는 파일 내용이 입력의 일부일 뿐이므로이 목적에 적합하지 않습니다. 분기의 초기 커밋의 경우에도 해시는 커밋 시간과 같이 커밋 메시지와 커밋 메타 데이터의 영향을받습니다. 동일한 디렉토리 구조를 여러 번 커밋하면 매번 다른 해시를 얻게되므로 결과 해시는 해시 만 전송하여 두 디렉토리가 서로의 정확한 복사본인지 여부를 결정하는 데 적합하지 않습니다.
Zoltan

1
@Zoltan 커밋 해시가 아닌 트리 해시를 사용하는 경우 git 해시는 완벽하게 괜찮습니다.
hobbs

1
@hobbs 대답은 원래 "커밋 해시"라고 말했는데,이 목적에는 맞지 않습니다. 트리 해시는 훨씬 더 나은 후보처럼 들리지만 여전히 숨겨진 함정이있을 수 있습니다. 내 마음에 떠오르는 것은 일부 파일에 실행 가능한 비트를 설정하면 트리 해시가 변경된다는 것입니다. git config --local core.fileMode false이것을 피하기 위해 커밋하기 전에 발행 해야합니다. 이와 같은 경고가 더 있는지 여부는 모르겠습니다.
Zoltan

14

넌 할 수있어 tar -c /path/to/folder | sha1sum


17
다른 시스템에서 해당 체크섬을 복제하려는 경우 형식이 모호 할 수있는 공간이 있고 여러 버전에 존재하는 것처럼 보이므로 tar가 좋은 선택이 아닐 수 있으므로 다른 시스템의 tar는 동일한 파일에서 다른 출력을 생성 할 수 있습니다.
slowdog 2011 년

2
slowdog의 유효한 문제에도 불구하고 파일 내용, 권한 등은 신경 쓰지만 수정 시간은 신경 쓰지 않는 경우 다음 --mtime과 같은 옵션을 추가 할 수 있습니다 tar -c /path/to/folder --mtime="1970-01-01" | sha1sum..
Binary Phile 2015

디렉토리 크기가 큰 경우 디렉토리의 크기를 압축하는과 더 많은 시간이 걸릴 것입니다에 MD5지고, 너무 큰 경우 @ S. 로트는, 내 말은
Kasun Siyambalapitiya

13

폴더의 내용이 변경되었는지 확인하려면 다음을 권장합니다.

ls -alR --full-time /folder/of/stuff | sha1sum

폴더, 하위 폴더, 파일, 타임 스탬프, 크기 및 권한을 포함하는 ls 출력의 해시 만 제공합니다. 무언가 변경되었는지 확인하는 데 필요한 거의 모든 것.

이 명령은 각 파일에 대해 해시를 생성하지 않지만 find를 사용하는 것보다 더 빠릅니다.


1
솔루션의 단순성을 고려할 때 이것이 왜 더 많은 찬성 투표를하지 않는지 잘 모르겠습니다. 왜 이것이 잘 작동하지 않는지 설명 할 수 있습니까?
데이브 C

1
내가 생성 된 해시 등 파일 소유자, 날짜 형식의 설정에 기반하므로이 좋지 않은 가정
료타

1
ls 명령은 원하는대로 출력하도록 사용자 정의 할 수 있습니다. -l을 -gG로 대체하여 그룹과 소유자를 생략 할 수 있습니다. --time-style 옵션을 사용하여 날짜 형식을 변경할 수 있습니다. 기본적으로 ls 매뉴얼 페이지를 확인하고 필요에 맞는 것을 확인하십시오.
Shumoapp

@DaveC 거의 쓸모가 없기 때문입니다. 파일 이름을 비교하려면 직접 비교하십시오. 그들은 그렇게 크지 않습니다.
Navin

7
@Navin 질문에서 파일 내용을 해시해야하는지 또는 트리의 변경 사항을 감지해야하는지 여부가 명확하지 않습니다. 각 케이스에는 용도가 있습니다. 예를 들어 커널 트리에 45K 파일 이름을 저장하는 것은 단일 해시보다 실용적이지 않습니다. ls -lAgGR --block-size = 1 --time-style = + % s | sha1sum 나를 위해 잘 작동합니다
yashma

5

강력하고 깨끗한 접근 방식

  • 먼저 , 사용 가능한 메모리를 잡아 먹지 마십시오 ! 전체 파일을 공급하는 대신 청크로 파일을 해시하십시오.
  • 다양한 요구 / 목적에 대한 다양한 접근 방식 (아래 모두 또는 적용되는 항목 선택) :
    • 디렉토리 트리에있는 모든 항목의 항목 이름 만 해시합니다.
    • 모든 항목의 파일 내용을 해시합니다 (메타를 그대로두고 inode 번호, ctime, atime, mtime, 크기 등).
    • 심볼릭 링크의 경우 내용은 참조 이름입니다. 해시하거나 건너 뛰도록 선택
    • 항목의 내용을 해싱하는 동안 심볼릭 링크를 따르거나 따르지 않을 (확인 된 이름)
    • 디렉토리 인 경우 내용은 디렉토리 항목 일뿐입니다. 재귀 적으로 순회하는 동안 그것들은 결국 해시 될 것이지만이 디렉토리에 태그를 지정하기 위해 해당 레벨의 디렉토리 항목 이름을 해시해야합니까? 콘텐츠를 해시하기 위해 깊이 탐색하지 않고도 변경 사항을 빠르게 식별하기 위해 해시가 필요한 사용 사례에 유용합니다. 예를 들어 파일의 이름이 변경되지만 나머지 내용은 동일하게 유지되고 모두 상당히 큰 파일입니다.
    • 대용량 파일을 잘 처리하십시오 (다시 RAM에 유의하십시오).
    • 매우 깊은 디렉토리 트리 처리 (열린 파일 설명자에 유의)
    • 비표준 파일 이름 처리
    • 소켓, 파이프 / 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

1
세 개의 하위 디렉토리가 있고 각각 몇 개의 파일이있는 Windows 폴더에 대해 강력하고 깨끗한 폴더 sha256을 얻는 간단한 예를 제공 할 수 있습니까?
Ferit

3

파일 내용을 해시하고 파일 이름을 무시하려면 다음을 사용할 수 있습니다.

cat $FILES | md5sum

해시를 계산할 때 파일이 동일한 순서로 있는지 확인하십시오.

cat $(echo $FILES | sort) | md5sum

그러나 파일 목록에는 디렉토리가있을 수 없습니다.


2
한 파일의 끝을 그 뒤에 오는 파일의 시작 부분으로 알파벳순으로 이동해도 해시에는 영향을주지 않지만 그래야합니다. 파일 구분 기호 또는 파일 길이는 해시에 포함되어야합니다.
제이슨 Stangroome

3

이를 달성하기위한 또 다른 도구 :

http://md5deep.sourceforge.net/

소리 그대로 : md5sum과 비슷하지만 재귀 적이며 다른 기능도 있습니다.


1
이 링크가 질문에 답할 수 있지만 여기에 답변의 필수 부분을 포함하고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 무효화 될 수 있습니다.
Mamoun Benghezal

3

이것이 git 저장소이고에서 파일을 무시 .gitignore하려면 다음을 사용할 수 있습니다.

git ls-files <your_directory> | xargs sha256sum | cut -d" " -f1 | sha256sum | cut -d" " -f1

이것은 나를 위해 잘 작동합니다.


감사합니다! :)
visortelle

많은 애플리케이션에서이 접근 방식이 우수합니다. 소스 코드 파일 만 해싱하면 훨씬 짧은 시간에 충분히 고유 한 해시를 얻을 수 있습니다.
John McGehee


2

파일 변경을 위해 전체 디렉토리를 확인해야했습니다.

그러나 제외, 타임 스탬프, 디렉토리 소유권.

목표는 파일이 동일한 경우 어디서나 동일한 합계를 얻는 것입니다.

파일이나 변경 사항을 제외하고는 다른 시스템에 호스팅되는 것을 포함합니다.

md5sum * | md5sum | cut -d' ' -f1

파일별로 해시 목록을 생성 한 다음 해당 해시를 하나로 연결합니다.

이것은 tar 방법보다 훨씬 빠릅니다.

A에 대한 강력한 개인 정보 보호 우리 해시에서, 우리는 사용할 수 sha512sum을 같은 조리법에.

sha512sum * | sha512sum | cut -d' ' -f1

해시는 sha512sum을 사용하는 곳 어디에서나 동일 하지만 뒤집을 수있는 알려진 방법이 없습니다.


이것은 디렉토리 해싱에 대한 대답보다 훨씬 간단 해 보입니다. 나는 믿을만한 대답을 찾지 못했습니다. 한 가지 문제 ... 해시가 다른 순서로 나올 가능성이 있습니까? sha256sum /tmp/thd-agent/* | sort내가 신뢰할 수있는 순서를 위해 노력하고있는 것입니다.
thinktt

안녕하세요, 해시가 기본적으로 알파벳순으로 제공되는 것 같습니다. 신뢰할 수있는 주문이란 무엇을 의미합니까? 모든 것을 스스로 정리해야합니다. 예를 들어 연관 배열 사용, 항목 + 해시. 그런 다음이 배열을 항목별로 정렬하면 계산 된 해시 목록이 정렬 순서로 제공됩니다. 그렇지 않으면 json 객체를 사용하고 전체 객체를 직접 해시 할 수 있다고 생각합니다.
NVRM

내가 당신이 말하는 것을 이해한다면 알파벳 순서로 파일을 해시합니다. 맞아 보인다. 위에서 받아 들여진 답변의 무언가가 때때로 간헐적으로 다른 명령을 내리는 것이 었으므로 다시는 발생하지 않도록 노력하고 있습니다. 나는 끝에 정렬을 계속할 것입니다. 작동하는 것 같습니다. 이 방법과 허용되는 대답의 유일한 문제는 중첩 폴더를 처리하지 않는다는 것입니다. 제 경우에는 폴더가 없으므로 훌륭하게 작동합니다.
thinktt

무엇에 대해 ls -r | sha256sum?
NVRM

@NVRM은 그것을 시도하고 파일 내용이 아닌 파일 이름 변경을 확인했습니다
Gi0rgi0s

1

두 단계로 만들어보십시오.

  1. 폴더의 모든 파일에 대해 해시가있는 파일 만들기
  2. 이 파일을 해시

이렇게 :

# 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

for F in 'find ...' ...이름에 공백이 있으면 작동하지 않습니다 (요즘 항상 그렇습니다).
mivk

1

개별 파일에 대한 결과를 sort(해시를 변경하기 위해 파일의 단순한 재정렬을 방지하기 위해) md5sum또는을 통해 파이프 sha1sum합니다.


1

이 작업을 수행하기 위해 Groovy 스크립트를 작성했습니다.

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

0

sha1sum해시 값 목록을 생성 한 다음 sha1sum그 목록을 다시 생성 할 수 있습니다. 정확히 무엇을 달성 하려는지에 따라 다릅니다.


0

다음은 다른 솔루션의 아이디어를 기반으로 빈 디렉토리를 무시하고 작은 크기의 파일 (예 : 모든 파일이 개별적으로 RAM에 쉽게 들어갈 수있는 소스 트리 또는 기타)에 대해 잘 작동하는 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()                          

다음과 같이 작동합니다.

  1. 디렉토리에서 모든 파일을 재귀 적으로 찾고 이름별로 정렬
  2. 모든 파일의 해시 (기본값 : SHA-1)를 계산합니다 (전체 파일을 메모리로 읽음).
  3. "filename = hash"줄로 텍스트 색인 만들기
  4. 해당 인덱스를 UTF-8 바이트 문자열로 다시 인코딩하고

SHA-1이 차 한잔이 아닌 경우 다른 해시 함수 를 두 번째 매개 변수로 전달할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.