2010-03-31 20 views
6

Necesito cambiar el nombre de forma recursiva de todos los archivos y directorios. Convierto espacios a guiones bajos y hago que todos los nombres de archivos/directorios estén en minúsculas. ¿Cómo puedo hacer que la siguiente secuencia de comandos cambie el nombre de todos los archivos en una sola ejecución? Actualmente, la secuencia de comandos debe ejecutarse varias veces antes de que se conviertan todos los archivos/directorios. El código es el siguiente:Perl: cambiar el nombre de todos los archivos y directorios

#!/usr/bin/perl 

use File::Find; 

$input_file_dir = $ARGV[0]; 

sub process_file { 
     $clean_name=lc($_); 
     $clean_name=~s/\s/_/g; 
     rename($_,$clean_name); 
     print "file/dir name: $clean_name\n"; 
} 
find(\&process_file, $input_file_dir); 
+2

¿Qué sucede si "Algunos Nombre de archivo" y "nombre_de_archivo" existen en el mismo directorio? Y para directorios no vacíos "Some Dir" y "some_dir" con el mismo padre? –

+0

¿Sabes que Perl viene con un script de cambio de nombre (3)? –

+0

@Pasi: es "prename". Por alguna razón, como de costumbre, Debian decidió cambiar las cosas y cambiarle el nombre para "cambiar el nombre", reemplazando el cambio de nombre original de userlinux. – Juliano

Respuesta

4

Usted sea necesario especificar bydepth => 1 en las opciones que se pasa a encontrar o llamar finddepth. De perldoc File::Find:

bydepth

informa del nombre de un directorio sólo después de todas sus entradas han sido reportados. El punto de entrada finddepth() es un atajo para especificar { bydepth => 1 } en el primer argumento de find().

Sin embargo, usted todavía tiene que decidir cómo hacer frente a los choques de nombres ya cambio de nombre será clobber el objetivo si el destino existe.

#!/usr/bin/perl 

use strict; use warnings; 
use File::Find; 

finddepth(\&process_file, $_) for @ARGV; 
1

si usted está abierto a otros enfoques, he aquí una solución Python

import os 
for R,DIR,FILES in os.walk("/mypath",topdown=False): 
    for file in FILES: 
     newfile=file.lower().replace(" ","_") 
     new_file_name=os.path.join(R,newfile) 
     os.rename(os.path.join(R,file) , new_file_name) 
    for dir in DIR: 
     newdir=dir.lower().replace(" ","_") 
     new_dir_name=os.path.join(R,newdir) 
     os.rename(os.path.join(R,dir) , new_dir_name) 
+0

Utilicé el script anterior y veo que funciona perfectamente bien. Gracias por compartir esto :) – Horizon

0

Puede cambiar el nombre de los archivos antes de atravesar a través de un directorio.

find({ 
     preprocess => sub { 
      for (@_) { 
       my $oldname = $_; 
       $_ = lc; 
       s/\s/_/g; 
       rename $oldname => $_; 
      } 
      return @_; 
     }, 
     wanted => sub { 
      print "$File::Find::name was already renamed\n"; 
     }, 
    }, 
    @dirs 
); 

O podría retrasar los renombrados hasta después de que se haya producido el cruce.

finddepth(sub { 
     print "in $File::Find::dir, renaming $_\n"; 
     my $newname = lc; 
     $newname =~ s/\s/_/g; 
     rename $_ => $newname; 
    }, 
    @dirs 
); 

El problema está encontrando es porque

find encuentra directorio "Abc Def"
find llamadas wanted("Abc Def")
      rename "Abc Def" => "abc_def"
find intenta entrar "Abc Def", que no existe más
      por lo que no se procesa todo lo que está debajo

Cuestiones relacionadas