Linux的:将1个百万个文件为基础的前缀创建的文件夹
题
我有一个名为“影像”充满了大约一万张图片的目录。是的。
我想要写一个外壳命令将所有这些图像的重命名为以下格式:
原始的filename.jpg
结果
新:的/f/i/l/filename.jpg
任何建议?
谢谢,结果 丹
解决方案
for i in *.*; do mkdir -p ${i:0:1}/${i:1:1}/${i:2:1}/; mv $i ${i:0:1}/${i:1:1}/${i:2:1}/; done;
在${i:0:1}/${i:1:1}/${i:2:1}
部分很可能是一个变量,或者更短的或不同的,但上面的命令能够完成任务。您可能会遇到性能问题,但如果你真的想使用它,缩小*.*
较少的选项(a*.*
,b*.*
或什么适合你)
编辑:$
为i
之前加入一个mv
,如丹指出
其他提示
可以使用,生成新的文件名例如,sed的:
$ echo "test.jpg" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/'
t/e/s/test.jpg
所以,你可以做这样的事情(假设已经创建了所有的目录):
for f in *; do
mv -i "$f" "$(echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/')"
done
或者,如果不能使用的bash $(
语法:
for f in *; do
mv -i "$f" "`echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/'`"
done
不过,考虑文件的数量,你可能只是想用perl因为这是很多SED和MV的过程中产卵:
#!/usr/bin/perl -w
use strict;
# warning: untested
opendir DIR, "." or die "opendir: $!";
my @files = readdir(DIR); # can't change dir while reading: read in advance
closedir DIR;
foreach my $f (@files) {
(my $new_name = $f) =~ s!^((.)(.)(.).*)$!$2/$3/$4/$1/;
-e $new_name and die "$new_name already exists";
rename($f, $new_name);
}
这是用perl当然仅限于相同的文件系统,虽然你可以使用File::Copy::move
要解决这个问题。
您可以做到这一点作为一个bash脚本:
#!/bin/bash
base=base
mkdir -p $base/shorts
for n in *
do
if [ ${#n} -lt 3 ]
then
mv $n $base/shorts
else
dir=$base/${n:0:1}/${n:1:1}/${n:2:1}
mkdir -p $dir
mv $n $dir
fi
done
不用说,你可能需要担心空间和文件用短名称。
我建议一个短Python脚本。大多数shell工具将在那么多输入望而却步(虽然xargs的可以做的伎俩)。将与例如在秒进行更新。
#!/usr/bin/python
import os, shutil
src_dir = '/src/dir'
dest_dir = '/dest/dir'
for fn in os.listdir(src_dir):
os.makedirs(dest_dir+'/'+fn[0]+'/'+fn[1]+'/'+fn[2]+'/')
shutil.copyfile(src_dir+'/'+fn, dest_dir+'/'+fn[0]+'/'+fn[1]+'/'+fn[2]+'/'+fn)
任何建议的解决方案,使用的外壳通配符语法很可能会失败,因为你有文件的数量之多。当前提出的解决方案的,perl的一个可能是最好的。
不过,您可以轻松地适应任何的shell脚本的方法来处理任意数量的文件这样的:
ls -1 | \
while read filename
do
# insert the loop body of your preference here, operating on "filename"
done
我仍然会用perl,但如果你只限于有简单的Unix工具身边,然后像我展示应该让你有结合上述外壳的解决方案之一,一环。这将是缓慢的,虽然。
不隶属于 StackOverflow