2011-12-09 20 views
7

Me gustaría tomar un directorio y para todos los archivos de correo electrónico (* .msg), elimine la 'RE' al comienzo. Tengo el siguiente código pero el cambio de nombre falla.Usando Perl para renombrar archivos en un directorio

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

Si imprime el error ($!) Usted puede tener una idea de lo que está mal ... – pilcrow

+0

Gracias por señalarlo. El error es 'No tal archivo o directorio'. Estoy sorprendido porque el nombre del archivo $ old es exacto. – Johnathan1

+2

Tenga en cuenta que 'rename' no cuenta con soporte multiplataforma, mientras que la función' move' de 'File :: Copy' hace – Zaid

Respuesta

9

Si el directorio de ./emails contiene estos archivos:

1.msg 
2.msg 
3.msg 

entonces su @files quedará del siguiente modo ('.', '..', '1.msg', '2.msg', '3.msg') pero su rename quiere nombres como 'emails/1.msg', 'emails/2.msg', etc. Por lo que puede cambiar el nombre de chdir antes:

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

Es probable que desee ch compruebe el valor de retorno chdir también.

o añadir los nombres de directorio usted mismo:

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 

Es posible que desee combinar su lectura directorio y filtrado usando grep:

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

o incluso esto:

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

Excelente. Gracias por explicar esto. – Johnathan1

5

Usted parece estar asumiendo glob -como el comportamiento en lugar de readdir -comportamiento similar.

La llamada al sistema subyacente readdir devuelve solo los nombres de archivo dentro del directorio, e incluirá dos entradas . y ... Esto lleva a la función readdir en Perl, solo para dar un poco más de detalle en la respuesta de mu.

Alternativamente, no tiene mucho sentido usar readdir si está recopilando todos los resultados en una matriz de todos modos.

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

+1 por recordarme que 'glob' existe. La desventaja de 'glob' es que complica el nombre un poco debido a la presencia del prefijo''emails '' ', es un problema bastante pequeño y trivial. –

2

Como ya se mencionó, su secuencia de comandos falla debido a la ruta que espera y los usos de la secuencia de comandos no son los mismos.

Sugiero un uso más transparente. Hardcoding un directorio no es una buena idea, IMO. Como supe un día cuando hice un script para alterar algunos archivos originales, con el camino codificado, y un colega mío pensó que sería un buen script para tomar prestado para alterar sus copias. Ooops!

Uso:

perl script.pl "^RE " *.msg 

es decir expresiones regulares, a continuación, una lista de archivos glob, en que la trayectoria se denota en relación con la secuencia de comandos, por ejemplo *.msg, emails/*.msg o incluso /home/pat/emails/*.msg /home/foo/*.msg. (múltiples globs posibles)

El uso de las rutas absolutas dejará al usuario sin ninguna duda en cuanto a qué archivos afectará, y también hará que la secuencia de comandos sea reutilizable.

Código:

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: Tengo que amar la Unix-ificación de Windows :) – Zaid

+0

Hola, me gusta mucho esta idea. Parece que estoy recibiendo un error en la línea my $ new = s/$ rx // r. La salida es 'bareword found where operator esperado cerca de' s/$ rx // r 'y error de sintaxis cerca del mismo – Johnathan1

+0

@JP. Oh, eso podría deberse a su versión perl ... ¿qué versión usa? – TLP

Cuestiones relacionadas