Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Renaming files in directory

by WisDomSeeKer34 (Sexton)
on Jan 05, 2018 at 20:14 UTC ( [id://1206784]=perlquestion: print w/replies, xml ) Need Help??

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

I want to rename files in a directory with this script:
#!bin/perl use strict; use warnings; use File::Copy qw(move); my $directory="/home/porter/blue"; my @names; opendir(DIR, $directory) or die "couldn't open $directory: $!\n"; my @files = readdir DIR; my $a = @files; @names = ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", +"m", "n", "o", "p"); for (my $i=0; $i < $a; $i ++) { move $files[$i], $names[$i]; }; closedir DIR;
And as result I get:
Use of uninitialized value $to in -d at /usr/share/perl/5.22/File/Copy +.pm line 256. Use of uninitialized value $to in stat at /usr/share/perl/5.22/File/Co +py.pm line 260. Use of uninitialized value $to in rename at /usr/share/perl/5.22/File/ +Copy.pm line 281. Use of uninitialized value $to in stat at /usr/share/perl/5.22/File/Co +py.pm line 291. Use of uninitialized value $to in string eq at /usr/share/perl/5.22/Fi +le/Copy.pm line 64. Use of uninitialized value $to in -d at /usr/share/perl/5.22/File/Copy +.pm line 96. Use of uninitialized value $to in stat at /usr/share/perl/5.22/File/Co +py.pm line 104. Use of uninitialized value $to in open at /usr/share/perl/5.22/File/Co +py.pm line 167. Use of uninitialized value $to in unlink at /usr/share/perl/5.22/File/ +Copy.pm line 30

What is the meaning of these errors? And can the script be improved?

Replies are listed 'Best First'.
Re: Renaming files in directory
by pryrt (Abbot) on Jan 05, 2018 at 21:08 UTC

    I think there are more files than names. (You could check this with print files => scalar(@files), "\n";). If that's the case, you might want @names = ('a'..'zz'); to make sure it's long enough. Or use the fact that perl can auto-increment strings, as in the example perl -le '$n = "a"; print ++$n for 1 .. 100'

    Also, don't ignore haukex++'s advice.

    edit: and as general debugging advice, when you see "uninitialized", it's a good idea to check if you're getting an undef somewhere; given it's in the $to, I assumed that meant the second argument to move was missing (and my tests show that passing move "source", undef does give those errors). If you need help finding the undef, print values before trying to use them.

Re: Renaming files in directory (updated)
by haukex (Archbishop) on Jan 05, 2018 at 21:02 UTC

    There are quite a few ways in which the code you showed can be improved.

    • You should use lexical filehandles, or rather in this case directory handles.
    • As documented in readdir, you need to prefix the directory name to the filenames returned, for example with catfile from File::Spec.
    • readdir will return every entry in the directory, including other directories, which you can filter with -X, and including the special entires . and .., which you can filter e.g. with no_upwards from File::Spec.
    • You should check the return value of move for errors.
    • I don't quite understand why you want to rename all the files to single letters, but consider this: what happens if readdir happens to return the filenames in a random order, or more filenames than you have letters for? This is why below I use sort and Perl's magic string increment.
    #!/usr/bin/env perl use warnings; use strict; use File::Copy qw/move/; use File::Spec::Functions qw/no_upwards catfile/; my $dir = "/home/porter/blue"; opendir my $dh, $dir or die "$dir: $!"; my @files = grep {-f} map {catfile $dir, $_} sort +no_upwards readdir $dh; closedir $dh; my $newname = "a"; for my $file (@files) { my $newfile = catfile($dir,$newname); print "$file -> $newfile\n"; # Debug move $file, $newfile or warn "$file: $!"; $newname++; }

    Update: Fixed: "sort no_upwards" was not correct, but the -f test was hiding the issue.

Re: Renaming files in directory
by Laurent_R (Canon) on Jan 05, 2018 at 23:02 UTC
    Hi WisDomSeeKer34,

    If you just want to rename files, then I would suggest that you just use the rename built-in function of Perl, rather than using the File::Copy module.

    Also, I would suggest that the glob function is, in at least 95% of the cases, much easier to use than the opendir/readdir combination for at least three reasons: it is simpler (one code line instead of two), it returns the filenames with their path (so you don't have to add the path yourself), and it removes special "files" such as . and .. from the file list.

    Then, unless you can really be sure that your file list will always have less than 16 files, don't hard code your list as you did. Increment you file names as you go, or build a much larger list, for example:

    my @names = ('a'..'zz');
    so that you can be sure you'll not run out of names.

    Finally, using a "c-style" loop is probably not a good idea (and it is really not perlish). You could try something like this (assuming you made the other changes I mentioned, especially glob):

    my $name = 'a'; for my $file_in (@files) { rename $file_in, $name; $name++; }
    Then, there is a slight problem: you don't say clearly where you want the output files to be created. Probably you want to first cd to the directory, or else want to change the loop above to:
    for my $file_in (@files) { rename $file_in, "$directory/$name"; $name++; }
    HTH.
      If you just want to rename files, then I would suggest that you just use the rename built-in function of Perl, rather than using the File::Copy module.

      why? "If possible, move() will simply rename the file."

        Sure, the move function the File::Copy module will rename the file, it is just a bit simpler to use a builtin function (such as rename) when it exists.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (3)
As of 2024-04-19 19:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found