2010-03-31 13 views
6

Potrzebuję rekursywnie zmienić nazwę każdego pliku i katalogu. Konwertuję spacje na podkreślniki i zamieniam wszystkie nazwy plików/katalogów na małe. Jak mogę zmienić nazwę wszystkich plików w jednym uruchomieniu? Obecnie skrypt musi być uruchamiany kilka razy, zanim wszystkie pliki/katalogi zostaną przekonwertowane. Kod jest poniżej:Perl: Rekurencyjnie zmień nazwę wszystkich plików i katalogów.

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

Co powinno się stać, jeśli "Some Filename" i "some_filename" oba istnieją w tym samym katalogu? A dla niepustych katalogów "Some Dir" i "some_dir" z tym samym rodzicem? –

+0

Czy wiesz, że perl pochodzi ze skryptu zmiany nazwy (3)? –

+0

@Pasi: to jest "prename". Z jakiegoś powodu, jak zwykle, Debian postanowił przełamać i zmienić nazwę na "zmień nazwę", zastępując oryginalną zmianę nazwy z userlinux. – Juliano

Odpowiedz

4

albo trzeba określić bydepth => 1 w opcjach można przejść do znalezienia lub zadzwoń finddepth. Od perldoc File::Find:

bydepth

Podaje nazwę katalogu dopiero po wszystkie jej wpisy zostały zgłoszone. Punkt wejścia finddepth() jest skrótem do określania { bydepth => 1 } w pierwszym argumencie z find().

Jednak trzeba jeszcze zdecydować, jak radzić sobie ze starć nazewnictwa, ponieważ zmiana nazwy będzie sprać cel jeśli cel istnieje.

#!/usr/bin/perl 

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

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

jeśli jesteś otwarty na innych podejść, oto rozwiązanie 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

Użyłem powyższego skryptu i widzę, że działa idealnie dobrze. Dzięki za udostępnienie tego :) – Horizon

0

Można zmieniać nazwy plików przed przejeżdżające przez Katalogu.

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

Można również opóźnić zmiany nazwisk, dopóki nie nastąpi przemiana.

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

Problem napotkania dlatego

find znajdzie directory "Abc Def"
find połączeń wanted("Abc Def")
      rename "Abc Def" => "abc_def"
find próbuje wejść "Abc Def", których już nie ma
      więc wszystko poniżej nie zostanie przetworzone

Powiązane problemy