2009-08-07 5 views

Odpowiedz

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} część prawdopodobnie mógłby być zmienną, lub krócej lub różne, ale przede polecenie dostaje zadanie. Prawdopodobnie będziesz twarz problemy z wydajnością, ale jeśli naprawdę chcesz go używać, zawężenie *.* do mniejszej liczby opcji (a*.*, b*.* lub co pasuje do Ciebie)

edit: dodaje $ przed i dla mv, jak zauważył Dan

+1

FYI, składnia '$ {i: 0: 1}' jest bash-ism, co jest prawdopodobnie OK w systemie Linux, ale na wszelki wypadek ... – derobert

+0

Jeśli w folderze jest kilka katalogów, czy ta pętla również je uwzględni? – Dan

+0

Potrzebna jedna korekta: dla i w *. *; do mkdir -p $ {i: 0: 1}/$ {i: 1: 1}/$ {i: 2: 1} /; mv $ i $ {i: 0: 1}/$ {i: 1: 1}/$ {i: 2: 1} /; Gotowe; – Dan

2

Można wygenerować nową nazwę pliku używając np sed:

$ echo "test.jpg" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/' 
t/e/s/test.jpg 

Tak, można zrobić coś takiego (zakładając, że wszystkie katalogi są już utworzone) :

for f in *; do 
    mv -i "$f" "$(echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/')" 
done 

lub, jeśli nie można użyć składni bash $(:

for f in *; do 
    mv -i "$f" "`echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/'`" 
done 

Jednak biorąc pod uwagę liczbę plików, może po prostu chcesz używać Perl jak to wiele procesów sed i mV do tarła:

#!/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 jest z pewnością ograniczona do osób tej samej plików tylko , ale możesz ominąć to za pomocą File::Copy::move.

+0

dzięki za to rozwiązanie, jest interesujące podejście – Dan

+0

oh, zauważyłem jedną rzecz, która testowanie mogłoby znaleźć: musi być test "czy to plik?" więc nie przesuwa katalogów. Dość łatwa do naprawienia (np. '-f $ f lub następna;' na początku pętli forel perla, podobnie w pętli powłoki) – derobert

1

Proponuję krótki skrypt Pythona. Większość narzędzi powłoki będzie się opierała na tak dużej ilości danych wejściowych (chociaż xargs może zrobić lewę). Zostanie zaktualizowane za pomocą przykładu w sekundę.

#!/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

dzięki, wygląda jak wspaniałe rozwiązanie. Muszę poczekać na przesłanie plików na mój nowy serwer, zanim będę mógł go przetestować (ETA 50 godzin lol) – Dan

2

można to zrobić za pomocą skryptu 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 

trzeba dodawać, że może trzeba się martwić o przestrzeni i plików z krótkimi nazwami.

+0

bardzo ładne rozwiązanie, dziękuję – Dan

0

Każde z proponowanych rozwiązań, które używają składni wieloznacznej w powłoce, prawdopodobnie nie powiedzie się z powodu dużej liczby posiadanych plików. Spośród obecnych proponowanych rozwiązań, prawdopodobnie jeden z nich jest najlepszy.

jednak można łatwo dostosować którąkolwiek z metod skrypt powłoki do czynienia z dowolnej liczby plików w następujący sposób:

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

Chciałbym jeszcze wykorzystać Perl, ale jeśli jesteś ograniczony tylko do konieczności prostych narzędzi unix wokół, a następnie połączenie jednego z powyższych rozwiązań powłoki z pętlą, tak jak pokazałem, powinno cię tam zabrać. Będzie to jednak powolne.

+0

Składnia symboli wieloznacznych powinna być dobra, jest wbudowana w powłokę i nie jest przekazywana z wiersza polecenia do programu w sposób zamierzony (w przeciwnym razie linia poleceń byłaby zbyt długa). na przykład w "seq 1 1000000" działa. – derobert

+0

Właśnie przetestowałem: używając 'for f in *' działa dobrze z 1 000 000 plików. Powolny, ale działa. – derobert

+0

dzięki za komentarz, to było pomocne, ponieważ jestem bardzo nowy w tworzeniu skryptów powłoki – Dan