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

Hi all, I have a directory with gzip'd files with the following format:
1999-04-22_weather.log.gz 1999-04-24_weather.log.gz 1999-04-25_weather.log.gz 1999-04-27_weather.log.gz You get the idea. Now suppose I want to see if files for a particular date range are available: my attempt at code is: ($nyear,$sdate,$edate) = @ARGV; ($sday,$smon) = split('-',$sdate); ($eday,$emon) = split('-',$edate); $sdate_cursor = [$nyear,$smon,$sday-1]; $edate_cursor = [$nyear,$emon,$eday]; @list = `ls -1 *_weather.*`; foreach $file (@list) { chomp($file); ($date,$dummy) = split(/\_/,$file); ($year,$month,$day) = split('-',$date); last if (compare_dates([$year,$month,$day], $edate_cursor) > 0); if (compare_dates([$year,$month,$day], $sdate_cursor) > 0 ) { push (@array, $file) if -e $file; } } sub compare_dates { my($a, $b) = @_; foreach (0..2) { if ($$a[$_]>$$b[$_]) { return 1; } elsif ($$a[$_]<$$b[$_]) { return -1; } } return 0; } As you can see from the list of files above, the files for the 23rd and 26th of April is missing. What could I do to get the script to report that these files are not present????? Thanks in advance. Stacy

Replies are listed 'Best First'.
Re: Does a file really exist?
by Masem (Monsignor) on Apr 19, 2001 at 03:56 UTC
    If you just want a warning, then change the push if -e line to..
    if -e $file { push @array, $file; } else { warn "$file does not exist\n"; }
    If you want to process such a list later, push the items into a second array:
    if -e $file { push @array, $file; } else { push @not_found, $file; }

    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: Does a file really exist?
by greenFox (Vicar) on Apr 19, 2001 at 06:02 UTC
    I think you are working way too hard :) Convert your dates to epoch seconds
    use Time::Local; my $time = timelocal(0,0,0,$mday,$month,$year);

    then your date comparisons become a simple numeric comparison

    also there is no need to make a system call to ls to get the filenames, a file glob would do

    @list = <*_weather.*>;

    update: I was working too hard as well :) Your dates are in a sensible format (yyyy-mm-dd), remove the dashes and you can just compare them numerically, much easier :)

    update2: thanks to tilly for pointing out I am still working too hard: yyyy-mm-dd can be compared with cmp no need to remove the dashes at all.

    --
    my $chainsaw = 'Perl';

Re: Does a file really exist?
by dws (Chancellor) on Apr 19, 2001 at 04:05 UTC
    Given the vagaries of date math (e.g., does this particular February have 28 days, or does this one have 29?), you might have better luck inverting the search. First build a list of ($year, $month, $day) triples that represent the dates within your search range, and then look to see if there's a corresponding file.

    Date::Calc will give you most of what you need.

      I am no expert but like the idea of tinkering with perl. What you can do is create a hash with the keys are all the dates between your start date and the end date. Traverse your directory and set the value of that key to 1.

      Now you have a hash with entries that indicate both existing and non-existing files for later processing.
Re: Does a file really exist?
by slife (Scribe) on Apr 20, 2001 at 19:24 UTC

    Slightly different input spec to your code ( and very simplistic output ), but this could easily be modified to suit. Abigail deserves the credit for the leap year code.

    #!/usr/local/bin/perl -w use strict; my $lastday= sub { $_[0] == 1 and return ( $_[0] % 4 ? 28 : $_[0] % 100 ? 29 : $_[0] % 400 ? 28 : 29 ); return ( qw~ 31 0 31 30 31 30 31 31 30 31 30 31 ~ )[$_[0]]; }; my $mon = $ARGV[0] ? $ARGV[0]-1 : (localtime( time ))[4]; my %days; @days{ 1 .. $lastday->($mon) } = (); opendir DIR, './' or die "Can\'t read from dir:$!"; for ( grep { /^.*?_weather/ } readdir DIR ) { my $day = $1 if /^(\d+?)-/; delete $days{$day} if $day; } close DIR; print map { join '' => $_, "\n" } sort { $a <=> $b } keys %days; __END__