Frage

Ich habe ein Verzeichnis namens "Bilder" mit ungefähr einer Million Bildern. Ja.

Ich möchte einen Shell -Befehl schreiben, um alle diese Bilder in das folgende Format umzubenennen:

Original: filename.jpg
Neu: /f/i/l/filename.jpg

Irgendwelche Vorschläge?

Vielen Dank,
Dan

War es hilfreich?

Lösung

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;

Das ${i:0:1}/${i:1:1}/${i:2:1} Der Teil könnte wahrscheinlich eine Variable oder kürzer oder unterschiedlich sein, aber der obige Befehl erledigt die Aufgabe. Sie werden wahrscheinlich mit Leistungsproblemen konfrontiert werden, aber wenn Sie es wirklich verwenden möchten, beschränken Sie die *.* zu weniger Optionen (a*.*, b*.* oder was passt zu dir)

Bearbeiten: Hinzugefügt a $ Vor i zum mv, wie von Dan festgestellt wurde

Andere Tipps

Sie können den neuen Dateinamen mit, z. B. SED generieren:

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

Sie können also so etwas tun (vorausgesetzt, alle Verzeichnisse sind bereits erstellt):

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

Oder wenn Sie die Bash nicht verwenden können $( Syntax:

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

In Anbetracht der Anzahl der Dateien möchten Sie jedoch nur Perl verwenden, da dies viele SED- und MV -Prozesse zum Laichen sind:

#!/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);
}

Dieser Perl ist sicherlich nur auf selbe Akteur beschränkt, obwohl Sie verwenden können File::Copy::move Um das umzugehen.

Sie können es als Bash -Skript tun:

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

Unnötig zu erwähnen, dass Sie sich möglicherweise um Leerzeichen und die Dateien mit kurzen Namen sorgen müssen.

Ich schlage ein kurzes Python -Skript vor. Die meisten Shell -Werkzeuge schließen so viel Eingabe ab (obwohl Xargs den Trick ausführen kann). Aktualisiert mit Beispiel in einer Sec.

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

Jede der vorgeschlagenen Lösungen, die eine Wildcard -Syntax in der Shell verwenden, wird aufgrund der schiere Anzahl von Dateien, die Sie haben, wahrscheinlich fehlschlagen. Von den aktuellen vorgeschlagenen Lösungen ist das Perl wahrscheinlich der beste.

Sie können jedoch problemlos jede der Shell -Skriptmethoden anpassen, um mit einer beliebigen Anzahl von Dateien umzugehen:

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

Ich würde immer noch Perl verwenden, aber wenn Sie nur darauf beschränkt sind, nur einfache Unix -Tools zu haben, sollte Sie eine der oben genannten Shell -Lösungen mit einer Schleife kombinieren, wie ich gezeigt habe, sollte Sie dorthin bringen. Es wird jedoch langsam sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top