Linux:将100万个文件移动到基​​于前缀的创建文件夹中

时间:2009-08-07 02:59:47

标签: linux shell file directory rename

我有一个名为“images”的目录,里面装满了大约一百万张图片。是的。

我想写一个shell命令将所有这些图像重命名为以下格式:

原文: filename.jpg
新: /f/i/l/filename.jpg

有什么建议吗?

谢谢,

5 个答案:

答案 0 :(得分:7)

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,如Dan所述

答案 1 :(得分:2)

您可以使用例如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来解决这个问题。

答案 2 :(得分:2)

您可以将其作为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

毋庸置疑,您可能需要担心空格和短名称的文件。

答案 3 :(得分:1)

我建议使用一个简短的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)

答案 4 :(得分:0)

任何在shell中使用通配符语法的建议解决方案都可能因为您拥有的文件数量而失败。在目前提出的解决方案中,perl可能是最好的。

但是,您可以轻松地调整任何shell脚本方法来处理任意数量的文件:

ls -1 | \
while read filename
do
  # insert the loop body of your preference here, operating on "filename"
done

我仍然会使用perl,但是如果你只能使用简单的unix工具,那么将上面的一个shell解决方案与我所展示的循环相结合应该可以帮到你。但它会很慢。