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

Hi Monks!
I need to compare dates on every text file found in a directory, and if the file contents are older than one moth from today's date, I need to archive from that point, how could I compare this:
our $localtime = localtime;
# This $localtime is going to give me: "Fri Jan 27 12:11:15 2006" as an example.
# I have to match against multiple lines in these text files, a directory could have multiple text files like that. error1.txt, error2.txt error-test.txt. And each line in each file starts like:
[Dec 23 15:40:06 2005] derror.txt : Test application module :: Error:: +file_log ::: Bad file descriptor
Now, if [Dec 23 15:40:06 2005] is one month older from today's date I have to delete that line from the file(s) and archive it.
I have got to a point where I can go through the directories and to the files, open all file contents, but now comes my problem, how to do what I explained before? Find in the files lines that are a month older, clear the lines with old stuff and archive it.
I have some code to show how far I could go.
Any help will be great!
## OPEN AND READ THE DIRECTORY #=comment opendir (DIR, "$dir"); my @FILES = grep(/.txt/,readdir(DIR)); closedir (DIR); foreach my $FILES (@FILES) { open FILE, "$dir/$FILES" or warn "Can't open $FILES: $!<br>\n", n +ext; while(<FILE>){ my $check = $_; + if($check=~/(^\[)(\w+)(\s)(\w+)(\s)(\d+)(.*?)$/isg){ print "**** $2** $4**$6**$7**<br>";} } close FILE; } }


Thanks a lot for the help!

jdporter added more code tags

Replies are listed 'Best First'.
Re: Comparing Dates
by duff (Parson) on Jan 27, 2006 at 19:28 UTC

    Convert your dates to a common, comparable representation. I typically use "seconds since 0000 Jan 1, 1970" aka "unix time" or "GMT". See the docs for Time::Local or try your hand at one of the date manipulation modules from CPAN (DateTime, Date::Manip, Date::Parse, etc.)

Re: Comparing Dates
by CountZero (Bishop) on Jan 27, 2006 at 20:46 UTC
    I may be misunderstanding you, but if I guess right you want to READ every line in the text-files (which are like some sort of log-files it seems), extract the date in each of these lines, compare that date to today's date and if older than 1 month, delete that line in the file and save it in some archive file.

    For date parsing and comparisons have a look at Date::Manip which is the Rolls Royce of date-modules, what it lacks in raw speed, it delivers in convenience.

    Generally, you could do as follows:

    1. open your archive file for adding to it
    2. open the first of your files for reading
    3. read this file line by line
    4. check the date in each line and if older than one month write it to the archive file, else push it onto a stack for temporary storage
    5. At the end of the file; close it and reopen it for writing (this will clear the contents of this file!); else goto step 3
    6. now write your temporary stack to this file (hint: use foreach)
    7. close the file
    8. open your next file; if no more files remain: close your archive file; else goto step 3

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      I think the original poster's code only gets files within the directory, not subdirectories. If the subdirectories are needed, then you could do a recursive solution, like -
      use File::Find; @ARGV = ('.') unless @ARGV; #start at . unless given # as command line argument sub ProcessFiles { &CheckAndFixFile($File::Find::name); } find(\&ProcessFiles, @ARGV); # find is recursive sub CheckAndFixFile { my $filename = shift @_; #Put code here to check if $filename meets criteria, and delete li +ne if needed. }

      The CheckAndFixFile subroutine is where you would use Date::Manip, or whichever Date module you like, to compare dates. It's easier than writing your own regular expression, as you did in your post, and it's code that's been tested and works.

Re: Comparing Dates
by ptum (Priest) on Jan 27, 2006 at 19:27 UTC

    Seems like you could use stat on each file and compare the mtime with time() - (86400 * 30) (or whatever). There is even File::stat which gives you a nice readable interface to the stat() attributes.


    No good deed goes unpunished. -- (attributed to) Oscar Wilde
Re: Comparing Dates
by philcrow (Priest) on Jan 27, 2006 at 19:26 UTC
    There are tons of date modules on CPAN which do lots of things, including comparing dates. I like Date::EzDate.

    Phil

    Update:I see you need times as well as dates. Try Date::Calc which handles times too.

Re: Comparing Dates
by tcf03 (Deacon) on Jan 29, 2006 at 12:32 UTC
    for a quick non perl solution and if you are using *nix just use find. typically what you do is do your first full backup and then touch a file at the end - say /etc/lastbackup. and then us find like this:
    find / -type f -newer /etc/lastbackup > /etc/backuplist


    Ted
    --
    "That which we persist in doing becomes easier, not that the task itself has become easier, but that our ability to perform it has improved."
      --Ralph Waldo Emerson
Re: Comparing Dates
by olus (Curate) on Jan 30, 2006 at 02:46 UTC
    This may give you an hint. It assumes current working directory. You can adapt it easilly.
    #!/usr/bin/perl -w use Date::Calc qw(Delta_Days); my $dirname = "."; my (@files, @log_lines); my %months = ( 'Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12, ); # get the list of text files opendir DIR, "$dirname"; @dircontent = grep { /\.txt$/ } readdir(DIR); closedir DIR; # Compute today's date my @today = (localtime(time))[3..5]; $today[1]++; $today[2] += 1900; # foreach text file, compute lines condition foreach $filename (@dircontent) { open FILE, "<$filename"; while(<FILE>) { my $line = $_; # see if line matches date format if($line =~ /^\[(\w{3}?) (\d{2}?)[^\]]*(\d{4}?)(.*)$/) { # assumed 'one month older' as being over 30 days. # if the line is older than 30 days, save it into an array # and write it later. If not, write it to a temp file (Delta_Days($3, $months{$1}, $2, $today[2], $today[1], $today[0] +) > 30 ) ? push @log_lines, $line : keep_line($line); } else { keep_line($line); } } close FILE; # The following lines restore the initial file but without old lines unlink $filename; rename "temp.tmp", $filename; } # archive old lines open ARCH, ">>archive.arc"; foreach $line (@log_lines) { print ARCH "$line"; } close ARCH; # Just append a line to temp file sub keep_line { my $line = shift; open TEMP, ">>temp.tmp"; print TEMP "$line"; close TEMP; }