要件のロジックは、bash の代わりに Python を使用することを正当化するのに十分なほど複雑です。より読みやすく、拡張性と保守性に優れたソリューションを提供する必要があります。
#!/usr/bin/env python
import hashlib, os
def ishash(h, size):
"""Whether `h` looks like hash's hex digest."""
if len(h) == size:
try:
int(h, 16) # whether h is a hex number
return True
except ValueError:
return False
for root, dirs, files in os.walk("."):
dirs[:] = [d for d in dirs if not d.startswith(".")] # skip hidden dirs
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
# extract old hash from the name; add/replace the hash if needed
barepath, ext = os.path.splitext(path) # ext may be empty
if not ishash(ext[1:], hashsize):
suffix += ext # add original extension
barepath, oldhash = os.path.splitext(barepath)
if not ishash(oldhash[1:], hashsize):
suffix = oldhash + suffix # preserve 2nd (not a hash) extension
else: # ext looks like a hash
oldhash = ext
if hash_ != oldhash: # replace old hash by new one
os.rename(path, barepath+suffix)
これはテスト用のディレクトリ ツリーです。を含む:
- 名前にドットが含まれるディレクトリ内の拡張子のないファイル
- すでにハッシュが含まれているファイル名 (冪等性のテスト)
- 2 つの拡張子を持つファイル名
- 名前の改行
$ツリー
a
|-- b
| | `-- CD
| | |-- f
| | |-- f.ext1.ext2
| | ` -- g.d41d8cd98f00b204e9800998ecf8427e
|-- c.ext^M改行
| | `-- f
`-- f^Jnewline.ext1
7 つのディレクトリ、5 つのファイル
結果
$ツリー
a
|-- b
| | `-- CD
| | |-- f.0bee89b07a248e27c83fc3d5951213c1
| | |-- f.ext1.614dd0e977becb4c6f7fa99e64549b12.ext2
| | ` -- g.d41d8cd98f00b204e9800998ecf8427e
|-- c.ext^M改行
| | `-- f.0bee89b07a248e27c83fc3d5951213c1
`-- f^Jnewline.b6fe8bb902ca1b80aaa632b776d77f83.ext1
7 つのディレクトリ、5 つのファイル
このソリューションは、すべてのケースで正しく機能します。
Whirlpool ハッシュは Python の stdlib にはありませんが、それをサポートする純粋な Python と C 拡張機能の両方がありますpython-mhash
。
インストールするには:
$ sudo apt-get install python-mhash
使用するには:
import mhash
print mhash.MHASH(mhash.MHASH_WHIRLPOOL, "text to hash here").hexdigest()
出力: cbdca4520cc5c131fc3a86109dd23fee2d7ff7be56636d398180178378944a4f41480b938608ae98da7eccbf39a4c79b83a8590c4cb1bace5bc638fc92b3e653
Pythonwhirlpooldeep
での呼び出し
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
ハッシュに基づいて一連のファイルを追跡する必要がある問題に活用できます。