-
12-09-2019 - |
题
问题的规范:
给予一个目录,我想迭代通过的目录及其非隐藏子目录,
并添加一个按摩的散列入非隐藏 文件的姓名。
如果剧本是重新运行,它将更换旧的散列一个新。
<filename>.<extension>
==><filename>.<a-whirlpool-hash>.<extension>
<filename>.<old-hash>.<extension>
==><filename>.<new-hash>.<extension>
问题:
a)如何要这么做?
b)从所有的方法提供给你,什么使你的方法最适合的?
判决:
谢谢,我已选择SeigeX的回答它的速度和可移植性。
这是emprically速度比其他砸变异体,
和它的工作没有改变我的Mac OS X机。
解决方案
更新,以修正:
1.文件名称中的'['或']'在他们的名字(真的,任何角色。见)
2.处理md5sum当的散列文件反斜杠或行在其名字
3.Functionized散列的检查algo模块化
4.重散列检查的逻辑来消除双重否定
#!/bin/bash
if (($# != 1)) || ! [[ -d "$1" ]]; then
echo "Usage: $0 /path/to/directory"
exit 1
fi
is_hash() {
md5=${1##*.} # strip prefix
[[ "$md5" == *[^[:xdigit:]]* || ${#md5} -lt 32 ]] && echo "$1" || echo "${1%.*}"
}
while IFS= read -r -d $'\0' file; do
read hash junk < <(md5sum "$file")
basename="${file##*/}"
dirname="${file%/*}"
pre_ext="${basename%.*}"
ext="${basename:${#pre_ext}}"
# File already hashed?
pre_ext=$(is_hash "$pre_ext")
ext=$(is_hash "$ext")
mv "$file" "${dirname}/${pre_ext}.${hash}${ext}" 2> /dev/null
done < <(find "$1" -path "*/.*" -prune -o \( -type f -print0 \))
这个代码具有以下好处超过其他项目迄今为止
- 它是完全符合Bash版本2.0.2外
- 没有多余调用其他的二进制文件如sed或查询;使用的系统参数的扩大而不是
- 使用过程中替换为"发现",而不是一个管道,没有子壳是由这种方式
- 需要目录工作,作为一个论点和不完整性检查它
- 使用$()而不是`符号指令取代,后者是废弃的
- 工作文件与空间
- 工作文件与新行
- 工作文件,与多个扩展
- 工作文件没有扩展
- 不遍历的隐藏目录
- 做 不 跳过前散列文件,它将重新计算的散列为每规范
测试树
$ tree -a a a |-- .hidden_dir | `-- foo |-- b | `-- c.d | |-- f | |-- g.5236b1ab46088005ed3554940390c8a7.ext | |-- h.d41d8cd98f00b204e9800998ecf8427e | |-- i.ext1.5236b1ab46088005ed3554940390c8a7.ext2 | `-- j.ext1.ext2 |-- c.ext^Mnewline | |-- f | `-- g.with[or].ext `-- f^Jnewline.ext 4 directories, 9 files
结果,
$ tree -a a a |-- .hidden_dir | `-- foo |-- b | `-- c.d | |-- f.d41d8cd98f00b204e9800998ecf8427e | |-- g.d41d8cd98f00b204e9800998ecf8427e.ext | |-- h.d41d8cd98f00b204e9800998ecf8427e | |-- i.ext1.d41d8cd98f00b204e9800998ecf8427e.ext2 | `-- j.ext1.d41d8cd98f00b204e9800998ecf8427e.ext2 |-- c.ext^Mnewline | |-- f.d41d8cd98f00b204e9800998ecf8427e | `-- g.with[or].d41d8cd98f00b204e9800998ecf8427e.ext `-- f^Jnewline.d3b07384d113edec49eaa6238ad5ff00.ext 4 directories, 9 files
其他提示
#!/bin/bash
find -type f -print0 | while read -d $'\0' file
do
md5sum=`md5sum "${file}" | sed -r 's/ .*//'`
filename=`echo "${file}" | sed -r 's/\.[^./]*$//'`
extension="${file:${#filename}}"
filename=`echo "${filename}" | sed -r 's/\.md5sum-[^.]+//'`
if [[ "${file}" != "${filename}.md5sum-${md5sum}${extension}" ]]; then
echo "Handling file: ${file}"
mv "${file}" "${filename}.md5sum-${md5sum}${extension}"
fi
done
- 测试文件,其中包含空间像'b'
- 测试文件,包含多个扩展,如'。b.c'
- 测试的目录,含有空间和/或点。
- 测试文件,其中包含没有扩展的内部目录的含点,例如'。b/c'
- 更新:现在更新如果哈希该文件的变化。
关键点:
- 使用
print0
通过管道输送到while read -d $'\0'
, ,以正确处理空间在文件名称。 - md5sum可以替换您最喜爱的散列函数。Sed删除第一空间和一切之后,它输出的md5sum.
- 基本文件名是取使用普通的表达,发现最后一个周期,是不是跟另一个斜线(所以这一时期的目录名称并不算作一部分的延伸)。
- 扩展是通过使用一串起始指数长度的基础文件。
逻辑的要求是复杂的,足以证明所使用的蟒蛇,而不是抨击。它应该提供一个更具可读性,可扩展,并可维护的解决方案。
#!/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)
这是一个测试的目录树。它包含:
- 文件没有扩展的内部目录的一点在他们的名字
- 文件已经散列在它(试验幂等性)
- 文件有两个扩展
- 新行中的名字
$ tree a a |-- b | `-- c.d | |-- f | |-- f.ext1.ext2 | `-- g.d41d8cd98f00b204e9800998ecf8427e |-- c.ext^Mnewline | `-- f `-- f^Jnewline.ext1 7 directories, 5 files
结果,
$ 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
该方案正常工作对于所有情况。
漩涡的散列是不是在蟒蛇的标准库,但那里都是纯Python和C的扩展,支持它,例如, python-mhash
.
安装它:
$ sudo apt-get install python-mhash
使用它:
import mhash
print mhash.MHASH(mhash.MHASH_WHIRLPOOL, "text to hash here").hexdigest()
输出:cbdca4520cc5c131fc3a86109dd23fee2d7ff7be56636d398180178378944a4f41480b938608ae98da7eccbf39a4c79b83a8590c4cb1bace5bc638fc92b3e653
调用 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
可以提供具有杠杆作用的问题,需要跟踪集的文件的基础上他们的散列。
我是不是真的快乐与我第一个回答,因为正如我所说,这一问题看起来就像是最好的解决perl。你已经说在一个编辑的问题是你有perl在OS X机器要运行这个,所以我给它一个镜头。
很难获得它所有的权利在庆典,即避免任何引述问题的奇怪的文件,并表现很好地角的情况的文件名。
所以在这里它是在perl,一个完整的解决您的问题。它运行了所有文件/目录上列出其命令行。
#!/usr/bin/perl -w
# whirlpool-rename.pl
# 2009 Peter Cordes <peter@cordes.ca>. Share and Enjoy!
use Fcntl; # for O_BINARY
use File::Find;
use Digest::Whirlpool;
# find callback, called once per directory entry
# $_ is the base name of the file, and we are chdired to that directory.
sub whirlpool_rename {
print "find: $_\n";
# my @components = split /\.(?:[[:xdigit:]]{128})?/; # remove .hash while we're at it
my @components = split /\.(?!\.|$)/, $_, -1; # -1 to not leave out trailing dots
if (!$components[0] && $_ ne ".") { # hidden file/directory
$File::Find::prune = 1;
return;
}
# don't follow symlinks or process non-regular-files
return if (-l $_ || ! -f _);
my $digest;
eval {
sysopen(my $fh, $_, O_RDONLY | O_BINARY) or die "$!";
$digest = Digest->new( 'Whirlpool' )->addfile($fh);
};
if ($@) { # exception-catching structure from whirlpoolsum, distributed with Digest::Whirlpool.
warn "whirlpool: couldn't hash $_: $!\n";
return;
}
# strip old hashes from the name. not done during split only in the interests of readability
@components = grep { !/^[[:xdigit:]]{128}$/ } @components;
if ($#components == 0) {
push @components, $digest->hexdigest;
} else {
my $ext = pop @components;
push @components, $digest->hexdigest, $ext;
}
my $newname = join('.', @components);
return if $_ eq $newname;
print "rename $_ -> $newname\n";
if (-e $newname) {
warn "whirlpool: clobbering $newname\n";
# maybe unlink $_ and return if $_ is older than $newname?
# But you'd better check that $newname has the right contents then...
}
# This could be link instead of rename, but then you'd have to handle directories, and you can't make hardlinks across filesystems
rename $_, $newname or warn "whirlpool: couldn't rename $_ -> $newname: $!\n";
}
#main
$ARGV[0] = "." if !@ARGV; # default to current directory
find({wanted => \&whirlpool_rename, no_chdir => 0}, @ARGV );
优点:-实际上使用的漩涡,因此可以使用这个确切的程序。(安装之后libperl摘要-漩涡).容易改变的任何消化功能你想要的,因为不是的不同的节目有不同的输出格式,你有perl摘要共同的接口。
实现所有其他要求:忽视的隐藏文件(下的文件和隐藏的目录).
能够处理任何可能的文件没有错误或安全问题。(几个人得到了这种权利在他们的外壳脚本)。
遵循最佳做法为历目录,通过chdiring下到每个目录(像我以前的答案,查找execdir).这样可以避免的问题PATH_MAX,与目录正在重新命名而你却在运行。
聪明的处理的文件名端。foo..txt...->foo..hash.txt...
处理旧文件含有的散列已经没有重新命名和重新命名他们回来。(它带任何序列的128hex digits这是围绕着"."字。) 在一切修正的情况下,没有盘写入活动的发生,只是读的每一个文件。你目前的解决方案运行mv两次在已经正确命名的情况下,造成目录的元数据写。和正在缓慢,因为这两个进程必须execced.
有效的。没有程序叉/execed,虽然大多数的解决方案实际上将工作结束了有sed的东西每文件。摘要::漩涡是实现本机编译的共用lib,所以它不是慢纯perl。这应该快于运行一个程序上的每一文件,esp。对于小的文件。
Perl支持UTF-8串,所以文件用非ascii characters不应该是一个问题。(不确定,如果任何multi-byte sequences UTF-8中可能包括的字节,这意味着ASCII'.'在其自己的。如果这是可能的,那么你需要UTF-8认识到串的处理。sed不知道UTF-8。庆典的团表达的可能。)
容易扩展。当你去把这个变成一个真正的程序,并要处理更多的情况,可以这样做相当不容易。例如决定要做什么,当你想要重新命名的文件,但哈希命名的文件已经存在。
好的错误报告。大多数的外壳脚本有这样的,不过,通过沿着错误的方案,他们运行。
find . -type f -print | while read file
do
hash=`$hashcommand "$file"`
filename=${file%.*}
extension=${file##*.}
mv $file "$filename.$hash.$extension"
done
您可能希望将结果存储在一个文件中,像
find . -type f -exec md5sum {} \; > MD5SUMS
如果你真的想每个哈希一个文件:
find . -type f | while read f; do g=`md5sum $f` > $f.md5; done
或甚至
find . -type f | while read f; do g=`md5sum $f | awk '{print $1}'`; echo "$g $f"> $f-$g.md5; done
下面是我采取它,在bash。特点:跳过非正规的文件;与在其名称怪异字符(即空格)的文件正确处理;涉及扩展名的文件名;跳过已经散列文件,因此它可以被重复运行(尽管如果文件被运行之间修改,增加了新的哈希值,而不是换旧人)。我写的使用MD5 -q作为哈希函数;你应该能够用别的来代替这一点,只要它仅输出哈希,不是像文件名=>散。
find -x . -type f -print0 | while IFS="" read -r -d $'\000' file; do
hash="$(md5 -q "$file")" # replace with your favorite hash function
[[ "$file" == *."$hash" ]] && continue # skip files that already end in their hash
dirname="$(dirname "$file")"
basename="$(basename "$file")"
base="${basename%.*}"
[[ "$base" == *."$hash" ]] && continue # skip files that already end in hash + extension
if [[ "$basename" == "$base" ]]; then
extension=""
else
extension=".${basename##*.}"
fi
mv "$file" "$dirname/$base.$hash$extension"
done
在SH或bash,两个版本。一个限制本身的文件具有扩展...
hash () {
#openssl md5 t.sh | sed -e 's/.* //'
whirlpool "$f"
}
find . -type f -a -name '*.*' | while read f; do
# remove the echo to run this for real
echo mv "$f" "${f%.*}.whirlpool-`hash "$f"`.${f##*.}"
done
...测试
...
mv ./bash-4.0/signames.h ./bash-4.0/signames.whirlpool-d71b117a822394a5b273ea6c0e3f4dc045b1098326d39864564f1046ab7bd9296d5533894626288265a1f70638ee3ecce1f6a22739b389ff7cb1fa48c76fa166.h
...
和此更复杂的版本处理所有纯文本文件,有或没有附加信息,有或没有空格和奇数字符,等等等等...
hash () {
#openssl md5 t.sh | sed -e 's/.* //'
whirlpool "$f"
}
find . -type f | while read f; do
name=${f##*/}
case "$name" in
*.*) extension=".${name##*.}" ;;
*) extension= ;;
esac
# remove the echo to run this for real
echo mv "$f" "${f%/*}/${name%.*}.whirlpool-`hash "$f"`$extension"
done
漩涡是不是一种非常常见的散列。您可能会需要安装一个程序来计算它。例如于Debian / Ubuntu包括“漩涡”包。该计划本身打印一个文件的哈希值。容易缓存搜索漩涡表明一些其他软件包支持,包括有趣md5deep。
一些早期anwsers将失败与空格的文件名。如果是这样的话,但你的文件没有任何换行符的文件名,那么你可以放心地使用\ n作为分隔符。
oldifs="$IFS"
IFS="
"
for i in $(find -type f); do echo "$i";done
#output
# ./base
# ./base2
# ./normal.ext
# ./trick.e "xt
# ./foo bar.dir ext/trick' (name "- }$foo.ext{}.ext2
IFS="$oldifs"
尝试没有设置IFS,看看它为什么重要。
我要尝试用IFS =东西“”;找到-print0 |而读-a阵列,分裂的“”人物,但我通常不会使用数组变量。有没有简单的方法,我在手册页看到插入的哈希值作为倒数第二个数组索引,并按下最后一个元素(文件扩展名,如果它有一个。)任何时候bash的数组变量看起来有趣,我知道它的时间做什么我做在Perl,而不是!请参阅使用读取的陷阱: http://tldp.org/LDP/abs/html/gotchas.html# BADREAD0
我决定使用另一种技术我喜欢:找到-exec SH -c。这是最安全的,因为你不能解析的文件名。
此应达到目的:
find -regextype posix-extended -type f -not -regex '.*\.[a-fA-F0-9]{128}.*' \
-execdir bash -c 'for i in "${@#./}";do
hash=$(whirlpool "$i");
ext=".${i##*.}"; base="${i%.*}";
[ "$base" = "$i" ] && ext="";
newname="$base.$hash$ext";
echo "ext:$ext $i -> $newname";
false mv --no-clobber "$i" "$newname";done' \
dummy {} +
# take out the "false" before the mv, and optionally take out the echo.
# false ignores its arguments, so it's there so you can
# run this to see what will happen without actually renaming your files.
-execdir的bash -c“CMD”虚设{} +具有虚设ARG那里,因为该命令之后的第一个参数变得$ 0 shell的位置参数,而不是“$ @”的是用于遍历的一部分。我用execdir聆听,而不是EXEC所以我没有处理目录名(或超过PATH_MAX的名称很长,当实际文件名是不够的所有短嵌套迪尔斯的可能性。)
- 未-regex可防止此被施加两次以相同的文件。虽然漩涡是一个非常长的哈希值,和mv说文件名太长,如果我跑了两次不办理入住手续。 (上XFS文件系统。)
文件不带扩展名获得basename.hash。我不得不检查专门以避免追加尾随,或获得基本名称作为扩展名。 ${@#./}去除前面的./是找到在每个文件名前放,所以不存在“”在整个字符串不带扩展名的文件。
MV --no-撞可以是GNU扩展。如果你没有GNU MV,怎么做,如果你想避免删除现有的文件(例如,你一旦运行此,一些相同的文件添加到目录中的旧名称。您再次运行)别的东西OTOH,如果你想要的行为,只是把它拿出来。
我的解决方案甚至应该工作的时候文件名包含一个换行符(他们可以,你懂的!),或任何其他可能的字符。这将是在Perl更快,更容易,但你问的外壳。
瓦伦博尔恩的用于制备一个文件的所有校验(而不是重命名原来的)的解决方案是非常好的,但效率不高。不要每个文件的md5sum运行一次,上一次运行它尽可能多的文件,将适合的命令行:
找到目录型的F -print0 | xargs的-0的md5sum> dir.md5 或者用GNU发现,xargs的是内置的(注意的+而不是“;”) 找到目录型的F -exec的md5sum {} +> dir.md5
如果你只是使用find -print | xargs的-d“\ n”,你会在他们引号文件名被搞砸了,所以要小心。如果你不知道哪些文件可能有一天运行该脚本,总是想用print0或-exec。这是ESP。如果为真文件名是由不受信任的用户提供的(即可以是你的服务器上的攻击向量。)
在响应于更新后的问题:
如果任何人都可以对我怎么能避免看在我的bash脚本隐藏目录评论,这将是大加赞赏。
您可以通过使用避免与发现隐藏的目录
find -name '.?*' -prune -o \( -type f -print0 \)
-name '.*' -prune
会修剪“”,并停止没有做任何事情。 :/
我还是会推荐我的Perl版本,虽然。我更新了它...您可能还需要从CPAN安装摘要::惠而浦,虽然。
嗯,有趣的问题。
试试下面(的mktest功能只是为了测试--TDD击!:)
编辑:
- 增加支持按摩的散列。
- 代码清理
- 更好地引用的文件名
- 改变列-语法测试的一部分--现在应该有最光辉-像炮弹。注意pdksh不支持:基于膨胀参数(或者说 这意味着别的东西)
还注意到,当在md5-模式的失败为名与漩涡-就像哈希, 可能反之亦然。
#!/usr/bin/env bash #Tested with: # GNU bash, version 4.0.28(1)-release (x86_64-pc-linux-gnu) # ksh (AT&T Research) 93s+ 2008-01-31 # mksh @(#)MIRBSD KSH R39 2009/08/01 Debian 39.1-4 # Does not work with pdksh, dash DEFAULT_SUM="md5" #Takes a parameter, as root path # as well as an optional parameter, the hash function to use (md5 or wp for whirlpool). main() { case $2 in "wp") export SUM="wp" ;; "md5") export SUM="md5" ;; *) export SUM=$DEFAULT_SUM ;; esac # For all visible files in all visible subfolders, move the file # to a name including the correct hash: find $1 -type f -not -regex '.*/\..*' -exec $0 hashmove '{}' \; } # Given a file named in $1 with full path, calculate it's hash. # Output the filname, with the hash inserted before the extention # (if any) -- or: replace an existing hash with the new one, # if a hash already exist. hashname_md5() { pathname="$1" full_hash=`md5sum "$pathname"` hash=${full_hash:0:32} filename=`basename "$pathname"` prefix=${filename%%.*} suffix=${filename#$prefix} #If the suffix starts with something that looks like an md5sum, #remove it: suffix=`echo $suffix|sed -r 's/\.[a-z0-9]{32}//'` echo "$prefix.$hash$suffix" } # Same as hashname_md5 -- but uses whirlpool hash. hashname_wp() { pathname="$1" hash=`whirlpool "$pathname"` filename=`basename "$pathname"` prefix=${filename%%.*} suffix=${filename#$prefix} #If the suffix starts with something that looks like an md5sum, #remove it: suffix=`echo $suffix|sed -r 's/\.[a-z0-9]{128}//'` echo "$prefix.$hash$suffix" } #Given a filepath $1, move/rename it to a name including the filehash. # Try to replace an existing hash, an not move a file if no update is # needed. hashmove() { pathname="$1" filename=`basename "$pathname"` path="${pathname%%/$filename}" case $SUM in "wp") hashname=`hashname_wp "$pathname"` ;; "md5") hashname=`hashname_md5 "$pathname"` ;; *) echo "Unknown hash requested" exit 1 ;; esac if [[ "$filename" != "$hashname" ]] then echo "renaming: $pathname => $path/$hashname" mv "$pathname" "$path/$hashname" else echo "$pathname up to date" fi } # Create som testdata under /tmp mktest() { root_dir=$(tempfile) rm "$root_dir" mkdir "$root_dir" i=0 test_files[$((i++))]='test' test_files[$((i++))]='testfile, no extention or spaces' test_files[$((i++))]='.hidden' test_files[$((i++))]='a hidden file' test_files[$((i++))]='test space' test_files[$((i++))]='testfile, no extention, spaces in name' test_files[$((i++))]='test.txt' test_files[$((i++))]='testfile, extention, no spaces in name' test_files[$((i++))]='test.ab8e460eac3599549cfaa23a848635aa.txt' test_files[$((i++))]='testfile, With (wrong) md5sum, no spaces in name' test_files[$((i++))]='test spaced.ab8e460eac3599549cfaa23a848635aa.txt' test_files[$((i++))]='testfile, With (wrong) md5sum, spaces in name' test_files[$((i++))]='test.8072ec03e95a26bb07d6e163c93593283fee032db7265a29e2430004eefda22ce096be3fa189e8988c6ad77a3154af76f582d7e84e3f319b798d369352a63c3d.txt' test_files[$((i++))]='testfile, With (wrong) whirlpoolhash, no spaces in name' test_files[$((i++))]='test spaced.8072ec03e95a26bb07d6e163c93593283fee032db7265a29e2430004eefda22ce096be3fa189e8988c6ad77a3154af76f582d7e84e3f319b798d369352a63c3d.txt'] test_files[$((i++))]='testfile, With (wrong) whirlpoolhash, spaces in name' test_files[$((i++))]='test space.txt' test_files[$((i++))]='testfile, extention, spaces in name' test_files[$((i++))]='test multi-space .txt' test_files[$((i++))]='testfile, extention, multiple consequtive spaces in name' test_files[$((i++))]='test space.h' test_files[$((i++))]='testfile, short extention, spaces in name' test_files[$((i++))]='test space.reallylong' test_files[$((i++))]='testfile, long extention, spaces in name' test_files[$((i++))]='test space.reallyreallyreallylong.tst' test_files[$((i++))]='testfile, long extention, double extention, might look like hash, spaces in name' test_files[$((i++))]='utf8test1 - æeiaæå.txt' test_files[$((i++))]='testfile, extention, utf8 characters, spaces in name' test_files[$((i++))]='utf8test1 - 漢字.txt' test_files[$((i++))]='testfile, extention, Japanese utf8 characters, spaces in name' for s in . sub1 sub2 sub1/sub3 .hidden_dir do #note -p not needed as we create dirs top-down #fails for "." -- but the hack allows us to use a single loop #for creating testdata in all dirs mkdir $root_dir/$s dir=$root_dir/$s i=0 while [[ $i -lt ${#test_files[*]} ]] do filename=${test_files[$((i++))]} echo ${test_files[$((i++))]} > "$dir/$filename" done done echo "$root_dir" } # Run test, given a hash-type as first argument runtest() { sum=$1 root_dir=$(mktest) echo "created dir: $root_dir" echo "Running first test with hashtype $sum:" echo main $root_dir $sum echo echo "Running second test:" echo main $root_dir $sum echo "Updating all files:" find $root_dir -type f | while read f do echo "more content" >> "$f" done echo echo "Running final test:" echo main $root_dir $sum #cleanup: rm -r $root_dir } # Test md5 and whirlpool hashes on generated data. runtests() { runtest md5 runtest wp } #For in order to be able to call the script recursively, without splitting off # functions to separate files: case "$1" in 'test') runtests ;; 'hashname') hashname "$2" ;; 'hashmove') hashmove "$2" ;; 'run') main "$2" "$3" ;; *) echo "Use with: $0 test - or if you just want to try it on a folder:" echo " $0 run path (implies md5)" echo " $0 run md5 path" echo " $0 run wp path" ;; esac
使用的zsh:
$ ls
a.txt
b.txt
c.txt
在魔术:
$ FILES=**/*(.)
$ # */ stupid syntax coloring thinks this is a comment
$ for f in $FILES; do hash=`md5sum $f | cut -f1 -d" "`; mv $f "$f:r.$hash.$f:e"; done
$ ls
a.60b725f10c9c85c70d97880dfe8191b3.txt
b.3b5d5c3712955042212316173ccf37be.txt
c.2cd6ee2c70b0bde53fbe6cac3c8b8bb1.txt
快乐解构!
编辑:在围绕mv
参数子目录和引号添加的文件
红宝石:
#!/usr/bin/env ruby
require 'digest/md5'
Dir.glob('**/*') do |f|
next unless File.file? f
next if /\.md5sum-[0-9a-f]{32}/ =~ f
md5sum = Digest::MD5.file f
newname = "%s/%s.md5sum-%s%s" %
[File.dirname(f), File.basename(f,'.*'), md5sum, File.extname(f)]
File.rename f, newname
end
把手具有空间,没有扩展,并且已经被散列的文件名。
忽略隐藏文件和目录。 - 如果这是所希望的添加File::FNM_DOTMATCH
作为glob
的第二个参数