这些需求的逻辑相当复杂,因此使用Python而非bash可以进行更好的处理。这将提供一种更易读、可扩展和可维护的解决方案。
import hashlib, os
def ishash(h, size):
"""Whether `h` looks like hash's hex digest."""
if len(h) == size:
try:
int(h, 16)
return True
except ValueError:
return False
for root, dirs, files in os.walk("."):
dirs[:] = [d for d in dirs if not d.startswith(".")]
for path in (os.path.join(root, f) for f in files if not f.startswith(".")):
suffix = hash_ = "." + hashlib.md5(open(path).read()).hexdigest()
hashsize = len(hash_) - 1
barepath, ext = os.path.splitext(path)
if not ishash(ext[1:], hashsize):
suffix += ext
barepath, oldhash = os.path.splitext(barepath)
if not ishash(oldhash[1:], hashsize):
suffix = oldhash + suffix
else:
oldhash = ext
if hash_ != oldhash:
os.rename(path, barepath+suffix)
Here's a test directory tree. It contains:
- files without extension inside directories with a dot in their name
- filename which already has a hash in it (test on idempotency)
- filename with two extensions
- newlines in names
```
$ tree a
a
|-- b
| `-- c.d
| |-- f
| |-- f.ext1.ext2
| `-- g.d41d8cd98f00b204e9800998ecf8427e
|-- c.ext^Mnewline
| `-- f
`-- f^Jnewline.ext1
7 directories, 5 files
```
Result
```
$ tree a
a
|-- b
| `-- c.d
| |-- f.0bee89b07a248e27c83fc3d5951213c1
| |-- f.ext1.614dd0e977becb4c6f7fa99e64549b12.ext2
| `-- g.d41d8cd98f00b204e9800998ecf8427e
|-- c.ext^Mnewline
| `-- f.0bee89b07a248e27c83fc3d5951213c1
`-- f^Jnewline.b6fe8bb902ca1b80aaa632b776d77f83.ext1
7 directories, 5 files
```
The solution works correctly for all cases.
Whirlpool hash is not in Python's stdlib, but there are both pure Python and C extensions that support it e.g., `python-mhash`.
To install it:
$ sudo apt-get install python-mhash
使用方法:
import mhash
print mhash.MHASH(mhash.MHASH_WHIRLPOOL, "text to hash here").hexdigest()
输出:
cbdca4520cc5c131fc3a86109dd23fee2d7ff7be56636d398180178378944a4f41480b938608ae98da7eccbf39a4c79b83a8590c4cb1bace5bc638fc92b3e653
在Python中调用whirlpooldeep
from subprocess import PIPE, STDOUT, Popen
def getoutput(cmd):
return Popen(cmd, stdout=PIPE, stderr=STDOUT).communicate()[0]
hash_ = getoutput(["whirlpooldeep", "-q", path]).rstrip()
Git
可以帮助解决需要基于哈希值跟踪一组文件的问题。
'.*'
(隐藏)目录。这是需要的吗? - jfs