Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Perl rename method

by iman_saleh (Novice)
on Dec 24, 2007 at 18:03 UTC ( #658908=perlquestion: print w/replies, xml ) Need Help??

iman_saleh has asked for the wisdom of the Perl Monks concerning the following question:

Hello all, I wrote a code that renames files, such that it changes the extension of any file to .xml extension. The program is recursive to traverse all files and subdirectories in a certain directory, and it takes a path of a directory as argument. However, the code I wrote does the renaming only for the first file in the folder and then displays an error message saying "No such file or directory" at the line performing renaming for any other file. I don't know why it is doing so. Can anyone please help me?
use Cwd; # module for finding the current working directory $|=1; # turn off I/O buffering # This subroutine takes the name of a directory and recursively scans # down the filesystem from that point looking for files named "core" sub ScanDirectory{ my ($workdir) = shift; print "Work dir = $workdir\n"; my ($startdir) = &cwd; # keep track of where we began chdir($workdir) or die "Unable to enter dir $workdir:$!\n"; opendir(DIR, ".") or die "Unable to open $workdir:$!\n"; my @names = readdir(DIR) or die "Unable to read $workdir:$!\n"; closedir(DIR); foreach my $name (@names){ next if ($name eq "."); next if ($name eq ".."); if (-d $name){ # is this a directory? &ScanDirectory($name); next; } else { # this is a file print "Name = $name\n"; $newName = $name; $newName =~ s/\..*//; $newName .= ".xml"; $result = rename($name, $newName) or die "cannot rename $name to $newName:$!"; } chdir($startdir) or die "Unable to change to dir $startdir:$!\n"; } } &ScanDirectory($ARGV[0]);

Replies are listed 'Best First'.
Re: Perl rename method
by FunkyMonk (Chancellor) on Dec 24, 2007 at 18:19 UTC
    chdir($startdir) should be outside the loop, shouldn't it?

    However, I'd look at a rewrite using File::Find or File::Find::Rule. The latter especially simplifies the task:

    use File::Find::Rule; my $start = shift || '.'; for my $oldname ( File::Find::Rule->file->in( $start ) ) { ( my $newname = $oldname ) =~ s/\..*?$//; rename $oldname, "$newname.xml" or die "..."; }

Re: Perl rename method
by ikegami (Pope) on Dec 24, 2007 at 18:39 UTC
    chdir($workdir) or die "Unable to enter dir $workdir:$!\n"; ... foreach my $name (@names){ ... if (-d $name){ &ScanDirectory($name); <-- This changes chdir. next; <-- Never changed back. } ... } ...

    Fix:

    use File::Spec::Functions qw( catfile ); # This subroutine takes the name of a directory and recursively scans # down the filesystem from that point looking for files named "core" sub ScanDirectory{ my $workdir = shift; if ($workdir =~ /^[a-zA-Z]:\z/) { $workdir .= '.'; # Fix bug in Windows. } print "Work dir = $workdir\n"; opendir(local *DIR, $workdir) or die "Unable to open $workdir: $!\n"; my @names = readdir(DIR) or die "Unable to read $workdir: $!\n"; closedir(DIR); foreach my $name (@names){ next if ($name eq "."); next if ($name eq ".."); my $fqname = catfile($workdir, $name); if (-d $fqname){ # is this a directory? ScanDirectory($fqname); next; } print "Name = $name\n"; $newName = $name; $newName =~ s/\..*//; $newName .= ".xml"; my $new_fqname = catfile($workdir, $newName); $result = rename($fqname, $new_fqname) or die "Cannot rename $fqname to $new_fqame: $!"\n; } } $|=1; # Turn off I/O buffering ScanDirectory($ARGV[0]);

    Better yet, let's remove needless recursion.

    use File::Spec::Functions qw( catfile ); # This subroutine takes the name of a directory and recursively scans # down the filesystem from that point looking for files named "core" sub ScanDirectory{ my $workdir = shift; if ($workdir =~ /^[a-zA-Z]:\z/) { $workdir .= '.'; # Fix bug in Windows. } my @todo = ( $workdir ); while (@todo) { my $workdir = shift(@todo); print "Work dir = $workdir\n"; opendir(local *DIR, $workdir) or die "Unable to open $workdir: $!\n"; my @names = readdir(DIR) or die "Unable to read $workdir: $!\n"; closedir(DIR); foreach my $name (@names){ next if ($name eq "."); next if ($name eq ".."); my $fqname = catfile($workdir, $name); if (-d $fqname){ # is this a directory? push @todo, $fqname; next; } print "Name = $name\n"; $newName = $name; $newName =~ s/\..*//; $newName .= ".xml"; my $new_fqname = catfile($workdir, $newName); $result = rename($fqname, $new_fqname) or die "Cannot rename $fqname to $new_fqame: $!"\n; } } } $|=1; # Turn off I/O buffering ScanDirectory($ARGV[0]);

    Btw, I properly scoped DIR (added local *DIR;) and removed requests to ignore prototypes (removed &).

    Update: Added fix.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://658908]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (10)
As of 2019-11-21 13:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (104 votes). Check out past polls.

    Notices?