2009-08-07 13 views

回答

6
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,由丹

注意
+1

仅供参考,'$ {i:0:1}'语法是bash-ism,可能是OK在Linux上,但以防万一... – derobert 2009-08-07 03:27:17

+0

如果文件夹中有几个目录,这个循环是否也包含它们? – Dan 2009-08-07 06:37:28

+0

需要一次更正: 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} /;完成; – Dan 2009-08-10 22:06:31

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来解决这个问题。

+0

感谢您的解决方案,这是一个有趣的方法 – Dan 2009-08-07 06:40:37

+0

哦,我注意到测试会发现的一件事情:需要测试“这是一个文件吗?”所以它不会移动目录。相当容易修复(例如,在perl foreach循环顶部的'-f $ f或next;',在shell循环中类似) – derobert 2009-08-08 05:30:53

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) 
+0

感谢,看起来像一个美妙的解决方案。我需要等待文件传输到我的新服务器才可以试用(ETA 50小时大声笑) – Dan 2009-08-07 06:38:19

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 

不用说,你可能需要担心的空间和一个带有短名的文件。

+0

非常好的解决方案,谢谢 – Dan 2009-08-07 06:41:45

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解决方案与我之前展示的一个循环结合起来,就可以让你在那里。不过,它会很慢。

+0

通配符语法应该没问题,它是一个内置的shell,并且它不是通过命令行传递给程序(否则,命令行将太长)。例如,我在'seq 1 1000000'作品中。 – derobert 2009-08-07 04:02:37

+0

我刚刚测试过:使用'for * in *'可以很好地处理1,000,000个文件。慢,但它的作品。 – derobert 2009-08-07 04:09:38

+0

感谢您的评论,这很有帮助,因为我对shell脚本非常陌生 – Dan 2009-08-07 06:42:40

相关问题