2011-12-09 19 views
7

Mi piacerebbe prendere una directory e per tutti i file di posta elettronica (* .msg), rimuovere la "RE" all'inizio. Ho il seguente codice ma il rinominare non riesce.Utilizzo di Perl per rinominare i file in una directory

opendir(DIR, 'emails') or die "Cannot open directory"; 
@files = readdir(DIR); 
closedir(DIR); 

for (@files){ 
    next if $_ !~ m/^RE .+msg$/; 
    $old = $_; 
    s/RE //; 
    rename($old, $_) or print "Error renaming: $old\n"; 
} 
+4

Se si stampa l'errore ($!) Si potrebbe avere un'idea di ciò che è sbagliato ... – pilcrow

+0

Grazie per la segnalazione. L'errore è "Nessun file o directory". Sono sorpreso perché il vecchio nome del file $ è accurato. – Johnathan1

+2

Si noti che 'rename' non gode del supporto multipiattaforma, mentre la funzione' move' di 'File :: Copia' fa – Zaid

risposta

9

Se la directory contenente i file ./emails:

1.msg 
2.msg 
3.msg 

allora il vostro @files avrà un aspetto simile ('.', '..', '1.msg', '2.msg', '3.msg') ma la vostra rename vuole nomi come 'emails/1.msg', 'emails/2.msg', ecc Così si può chdir prima di rinominare:

chdir('emails'); 
for (@files) { 
    #... 
} 

Probabilmente vorrai ch eck anche il valore di ritorno chdir.

o aggiungere i nomi di directory da soli:

rename('emails/' . $old, 'emails/' . $_) or print "Error renaming $old: $!\n"; 
# or rename("emails/$old", "emails/$_") if you like string interpolation 
# or you could use map if you like map 

Si potrebbe desiderare di combinare la lettura di directory e filtraggio con grep:

my @files = grep { /^RE .+msg$/ } readdir(DIR); 

o anche questo:

opendir(DIR, 'emails') or die "Cannot open directory"; 
for (grep { /^RE .+msg$/ } readdir(DIR)) { 
    (my $new = $_) =~ s/^RE //; 
    rename("emails/$_", "emails/$new") or print "Error renaming $_ to $new: $!\n"; 
} 
closedir(DIR); 
+0

Eccellente. Grazie per aver spiegato questo. – Johnathan1

5

È sembra assumere il comportamento glob -like anziché readdir -come il comportamento.

La chiamata di sistema readdir sottostante restituisce solo i nomi file all'interno della directory e includerà due voci . e ... Questo porta fino alla funzione readdir in Perl, solo per dare un po 'più di dettaglio sulla risposta di mu.

In alternativa, non c'è molto senso usare readdir se si stanno raccogliendo comunque tutti i risultati in un array.

@files = glob('emails/*'); 
+0

+1 per avermi ricordato che 'glob' esiste. Lo svantaggio di 'glob' è che complica il nome maneggiando un po 'a causa della presenza del prefisso' 'email /'', che è un problema piuttosto secondario e banale da affrontare però. –

2

Come già accennato, lo script non riesce a causa del percorso previsto e gli usi dello script non sono gli stessi.

Vorrei suggerire un utilizzo più trasparente. L'hardcoding di una directory non è una buona idea, IMO. Come ho appreso un giorno quando ho realizzato una sceneggiatura per alterare alcuni file originali, con il percorso hardcoded, e un mio collega ha pensato che sarebbe stata una bella sceneggiatura da prendere in prestito per alterare le sue copie. Ops!

utilizzati:

perl script.pl "^RE " *.msg 

cioè regex, quindi un elenco di file glob, dove il percorso è indicato in relazione allo script, ad esempio *.msg, emails/*.msg o anche /home/pat/emails/*.msg /home/foo/*.msg. (più globi possibili)

L'utilizzo dei percorsi assoluti non lascia dubbi all'utente sui file che inciderà e renderà lo script riutilizzabile.

Codice:

use strict; 
use warnings; 
use v5.10; 
use File::Copy qw(move); 

my $rx = shift; # e.g. "^RE " 

if ($ENV{OS} =~ /^Windows/) { # Patch for Windows' lack of shell globbing 
    @ARGV = map glob, @ARGV; 
} 

for (@ARGV) { 
    if (/$rx/) { 
     my $new = s/$rx//r; # Using non-destructive substitution 
     say "Moving $_ to $new ..."; 
     move($_, $new) or die $!; 
    } 
} 
+0

+1: Devo amare Unix-ificazione di Windows :) – Zaid

+0

Ciao, mi piace molto questa idea. Mi sembra di avere un errore sulla linea my $ new = s/$ rx // r. L'output è "bareword trovato dove l'operatore si aspetta vicino a" s/$ rx // r "e l'errore di sintassi vicino allo stesso – Johnathan1

+0

@ JP. Oh, potrebbe essere dovuto alla tua versione perl .. quale versione usi? – TLP

Problemi correlati