Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

rename files with mtime

by pbaumgar (Acolyte)
on Feb 14, 2009 at 19:31 UTC ( [id://743856]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I'm writing a perl script to rename some old log file with the date the file was last modified to be in the file name. Example: maillog.1.gz rename to maillog.20090213.gz. Here's what I have written so far. It sorts the files newest to oldest and then prints the new filename with the mtime, replacing the digit between maillog and gz. I'm not very experienced with perl, so I'm looking for advice if what I have written is any good and how it could be improved. Thanks for your help!
#!/usr/bin/perl -w use strict; use File::stat; use POSIX qw(strftime); my $maillog_dir = '/var/log/maillogs'; opendir ( LOG, $maillog_dir) or die ("Can't open $maillog_dir: $!"); my @list = sort { -M "$maillog_dir/$a" <=> -M "$maillog_dir/$b" } grep { -f "$maillog_dir/$_" } readdir ( LOG ); foreach my $file ( @list ){ my $datestamp = strftime("%Y%m%d", localtime(stat("$maillog_di +r/$file")->mtime)); $file =~ s/\d+/$datestamp/; print "$file\n"; } close ( LOG );

Replies are listed 'Best First'.
Re: rename files with mtime
by GrandFather (Saint) on Feb 14, 2009 at 20:00 UTC

    opendir requires closedir (not close).

    A common technique when using sort is to precalculate anything expensive (-M in this case) using a map before the sort then extract the desired data using another map after the sort:

    my @list = map {$_->[1]} sort { $a->[0] <=> $b->[0] } map {[-M "$maillog_dir/$_", $_]} ...

    True laziness is hard work
Re: rename files with mtime
by CountZero (Bishop) on Feb 14, 2009 at 20:53 UTC
    Ask yourself, "Why do I have to sort the log-files according to their mtime?". strftime or the filesystem could not care less whether your rename the files in sorted order or not.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: rename files with mtime
by Narveson (Chaplain) on Feb 15, 2009 at 03:56 UTC

    You do realize, I trust, that your program does not rename any files?

    $file =~ s/\d+/$datestamp/ changes the contents of your variable $file. To use your own example, if $file contains maillog.1.gz and the datestamp is 20090213, then after the substitution $file will contain maillog.20090213.gz. The file on disk, however, is still named maillog.1.gz.

    You are wise to be printing the outcome of the substitution so that you can review it. Assuming you are satisfied with your printout, how are you going to rename the file? In order to follow the template for rename, which is

    rename OLDNAME,NEWNAME

    you'll need to declare a second variable. The idiomatic way is

    (my $new_name = $file) =~ s/\d+/$datestamp/;

    after which you can say

    rename $file, $new_name;

      Speaking of idioms...

      after which you can say
      rename $file, $new_name;

      The following idiom helps prevents renaming disasters:

      rename $file, $new_name unless -e $new_name;

      That is, don't rename a file if it would cause an existing file to be unlinked. It's easier to fix up the mess of a file that hasn't been renamed than one that no longer exists...

      • another intruder with the mooring in the heart of the Perl

Re: rename files with mtime
by oko1 (Deacon) on Feb 15, 2009 at 20:23 UTC

    In addition to the problems noted by others, it seems like sorting first and renaming afterwards would be a waste of effort; "%Y%m%d" will automatically sort correctly in most situations, which is part of the point of doing it that way. Also, if you start renaming your files and run into a duplicate date part-way through, you'll end up with a scattered list of filenames. It would be better to validate before you ever start renaming. You might want to consider something like this:

    #!/usr/bin/perl -w use strict; use POSIX; my %seen; while (<*.gz>){ my $date = strftime "%Y%m%d", localtime((lstat($_))[9]); my $was = $_; s/\d+/$date/; die "File '$_' already exists!\n" if -f $_; die "We already have a file with that date ($date).\n" if $seen{$_ +}; $seen{$_} = $was; } for my $fn (sort keys %seen){ rename $seen{$fn}, $fn; print "$fn\n"; }

    --
    "Language shapes the way we think, and determines what we can think about."
    -- B. L. Whorf

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2024-04-20 03:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found