Linux:为给定文件夹计算单个哈希值&;目录
当然,一定有办法轻松做到这一点 我尝试过Linux命令行应用程序,如Linux:为给定文件夹计算单个哈希值&;目录,linux,bash,hash,Linux,Bash,Hash,当然,一定有办法轻松做到这一点 我尝试过Linux命令行应用程序,如sha1sum和md5sum,但它们似乎只能计算单个文件的哈希值并输出哈希值列表,每个文件一个 我需要为文件夹的全部内容(不仅仅是文件名)生成一个散列 我想做点像 sha1sum /folder/of/stuff > singlehashvalue 编辑:为了澄清,我的文件位于目录树中的多个级别,它们不都位于同一根文件夹中。如果您只想对文件内容进行哈希运算,而忽略文件名,则可以使用 cat $FILES | md5sum
sha1sum
和md5sum
,但它们似乎只能计算单个文件的哈希值并输出哈希值列表,每个文件一个
我需要为文件夹的全部内容(不仅仅是文件名)生成一个散列
我想做点像
sha1sum /folder/of/stuff > singlehashvalue
编辑:为了澄清,我的文件位于目录树中的多个级别,它们不都位于同一根文件夹中。如果您只想对文件内容进行哈希运算,而忽略文件名,则可以使用
cat $FILES | md5sum
计算哈希时,请确保文件的顺序相同:
cat $(echo $FILES | sort) | md5sum
但您的文件列表中不能有目录。请尝试分两步进行:
# 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
您可以
sha1sum
生成散列值列表,然后sha1sum
再次生成该列表,这取决于您想要完成的具体操作。我将通过排序
对单个文件的结果进行管道处理(以防止仅仅对文件进行重新排序以更改散列)进入md5sum
或sha1sum
,无论您选择哪个。一种可能的方法是:
sha1sum path/to/folder/* | sha1sum
stat
的参数将使其打印文件名,后跟八进制权限。这两个查找将依次运行,导致磁盘IO量加倍,第一个查找所有文件名并对内容进行校验和,第二个查找所有文件名和目录名,打印名称和模式。然后将对“文件名和校验和”列表,后跟“名称和目录,具有权限”进行校验和,以获得较小的校验和。- 使用文件系统入侵检测工具,如
- 散列目录的tar球:
tar cvf-/path/to/folder|sha1sum
- 自己编写代码,比如:
find/path/to/folder-type f-print0 | sort-z | xargs-0 sha1sum | sha1sum
- 您可以执行
tar-c/path/to/folder | sha1sum
有一个python脚本:
如果更改文件名而不更改其字母顺序,哈希脚本将不会检测到它。但是,如果您更改了文件的顺序或任何文件的内容,运行脚本将得到与以前不同的哈希值。另一个实现此目的的工具: 原样听起来:像md5sum,但也是递归的,再加上其他特性
md5deep-r{direcotory}
我编写了一个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)}"
如果您只想检查文件夹中的内容是否发生了更改,我建议您:
ls -alR --full-time /folder/of/stuff | sha1sum
它只会给您一个ls输出的散列,其中包含文件夹、子文件夹、它们的文件、时间戳、大小和权限。几乎所有你需要确定的事情都发生了变化
请注意,此命令不会为每个文件生成哈希,但这就是为什么它应该比使用find更快的原因 稳健而干净的方法
- 首先,不要占用可用内存!将文件分块散列,而不是填充整个文件李>
- 针对不同需求/目的的不同方法(以下所有方法或选择适用的方法):
- 仅哈希目录树中所有条目的条目名称
- 散列所有条目的文件内容(保留meta-like、inode-number、ctime、atime、mtime、size等,你就知道了)
- 对于符号链接,其内容是引用名称。散列或选择跳过
- 对条目内容进行哈希运算时,是否跟随(解析名称)符号链接
- 如果它是一个目录,它的内容就是目录条目。当递归遍历时,它们最终将被散列,但是该级别的目录条目名称是否应该被散列以标记该目录?在需要散列以快速识别更改而不必深入遍历以散列内容的用例中非常有用。例如,文件名更改,但其余内容保持不变,它们都是相当大的文件
- 很好地处理大文件(同样,注意RAM)
- 处理非常深的目录树(注意打开的文件描述符)
- 处理非标准文件名
- 如何处理套接字、管道/FIFO、块设备、字符设备等文件?你也必须把它们弄散吗
- 在遍历时不要更新任何条目的访问时间,因为对于某些用例来说,这将是一个副作用和反作用(直观?)
dtreetrawl
的使用和输出示例。
人性化输出的一个片段:
我必须检查整个目录中的文件更改 但不包括时间戳、目录所有权 目标是在文件相同的情况下,在任何地方获得相同的总和 包括托管到其他计算机,而不考虑文件或对其进行更改
md5sum * | md5sum | cut -d' ' -f1
它按文件生成一个散列列表,然后将这些散列连接成一个列表
这比tar方法快得多
为了在散列中获得更好的隐私,我们可以在同一配方上使用sha512sum
sha512sum * | sha512sum | cut -d' ' -f1
使用sha512sum时,散列值在任何地方都是相同的,但是没有已知的方法来反转散列值。这里是Python 3中的一个简单、简短的变体,适用于小文件
ls -alR --full-time /folder/of/stuff | sha1sum
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
md5sum * | md5sum | cut -d' ' -f1
sha512sum * | sha512sum | cut -d' ' -f1
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()
git ls-files <your_directory> | xargs sha256sum | cut -d" " -f1 | sha256sum | cut -d" " -f1
tar -C <root-dir> -cf - --sort=name <dir> | sha256sum
100%|██████████████████████████████████| 31378/31378 [03:03<00:00, 171.43file/s]