Domanda

Ho una directory chiamata "immagini" riempiti con circa un milione di immagini. Sì.

Voglio scrivere un comando di shell per rinominare tutte quelle immagini nel seguente formato:

originale: filename.jpg
nuovo: /f/i/l/filename.jpg

Qualche suggerimento?

Grazie,
Dan

È stato utile?

Soluzione

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;

La parte ${i:0:1}/${i:1:1}/${i:2:1} probabilmente potrebbe essere una variabile, o più corto o diversi, ma il comando sopra ottiene il lavoro fatto. Probabilmente affrontare problemi di prestazioni, ma se si vuole veramente usarlo, restringere il *.* a un minor numero di opzioni (a*.*, b*.* o quello che si adatta)

edit: aggiunto un $ prima i per mv, come notato da Dan

Altri suggerimenti

È possibile generare il nuovo nome del file utilizzando, ad esempio, sed:

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

Quindi, si può fare qualcosa di simile (assumendo che tutte le directory sono già stati creati):

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

o, se non è possibile utilizzare la sintassi bash $(:

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

Tuttavia, considerando il numero di file, si può fare, a usare perl in quanto questo è un sacco di processi sed e mv per deporre le uova:

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

che Perl è sicuramente limitato solo tra persone dello stesso file system, anche se è possibile utilizzare File::Copy::move per aggirare questo.

Si può fare come uno script 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

Inutile dire, potrebbe essere necessario preoccuparsi di spazi e i file con nomi brevi.

Suggerisco uno script python breve. La maggior parte degli strumenti di shell saranno esitano a più di tanto di ingresso (anche se xargs possono fare il trucco). Aggiornerà con l'esempio in un secondo.

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

Qualsiasi delle soluzioni proposte che utilizzano una sintassi jolly nella shell probabilmente non riuscire a causa del gran numero di file che avete. Tra le soluzioni proposte attuali, il perl è probabilmente il migliore.

Tuttavia, si può facilmente adattare qualsiasi dei metodi di script di shell a che fare con qualsiasi numero di file in tal modo:

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

Vorrei ancora usare perl, ma se si è limitato ad avere solo semplici strumenti Unix intorno, poi combina una delle soluzioni guscio di cui sopra con un ciclo come ho mostrato dovrebbe arrivare lì. Sarà lento, però.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top