我有一个名为“images”的目录,里面有大约一百万张图片。是的。
我想编写一个 shell 命令将所有这些图像重命名为以下格式:
原: 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*.*
适合您的选项)
编辑:如 Dan 所述,在for$
之前添加了一个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)
由于您拥有的文件数量庞大,任何在 shell 中使用通配符语法的建议解决方案都可能会失败。在当前提出的解决方案中,perl 可能是最好的。
但是,您可以轻松地调整任何 shell 脚本方法来处理任意数量的文件,因此:
ls -1 | \
while read filename
do
# insert the loop body of your preference here, operating on "filename"
done
我仍然会使用 perl,但如果您仅限于使用简单的 unix 工具,那么将上述 shell 解决方案之一与我展示的循环结合起来应该可以帮助您。不过会很慢。