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

I'm writing some code to handle multiple data communications scripts, and I'm trying to pull the server info, paths, and schedules into a config file so that comm process flows are easier to track.

I'd like to pull the schedule lines from our crontab file (which is overgrown and mainly contains lines unrelated to comm processes), and keep the same format.

I've seen a few cron-related modules on Cpan, but I'm interested in just parsing a schedule line and comparing it to the current date/time to see when the job should have last kicked off. I'd like to avoid installing a module to do this, but I can if I need to.

Anyone have any cron-parsing snippets laying around, module-dependent or otherwise?

Replies are listed 'Best First'.
Re: Parsing a crontab line
by Corion (Patriarch) on Nov 05, 2003 at 14:42 UTC

    Have you looked at Schedule::Cron? It has good crontab compatibility, and I think that you can rip out the crontab parser relatively easy.

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: Parsing a crontab line
by belg4mit (Prior) on Nov 05, 2003 at 16:12 UTC
    I wrote a custom parser in a cron; in perl.

    --
    I'm not belgian but I play one on TV.

Re: Parsing a crontab line
by vek (Prior) on Nov 05, 2003 at 17:16 UTC
Re: Parsing a crontab line
by delirium (Chaplain) on Nov 05, 2003 at 18:44 UTC
    Thanks for everyone's input. A couple of the scripts gave me some good ideas, but I ended up rolling my own. It still needs a little tweaking, but here's what I have so far:

    #!/usr/bin/perl -w use strict; sub cron_parse { # This routine takes a time (seconds since epoch) and a crontab entry, + and returns # the next time the process would kick off. Pass the script the last t +ime a job ran, # and the cron entry, and compare the result to the current date. This + will tell you # if the job is overdue. The cron entry passed should contain only the + 5 schedule # columns. Day-of-month and Month are ignored (my processes don't use +them). # If anything is wrong with the input, undef is returned. my $last = shift || return undef; my @last = localtime($last); # 1 - minutes, 2 - hours, 6 - day +of week $last = (1440 * $last[6]) + (60 * $last[2]) + $last[1]; $_ = shift || return undef; my @cron_array = split; return undef unless $#cron_array == 4; my $minutes = &cron_range_populate (59, $cron_array[0]) || return +undef; my $hours = &cron_range_populate (23, $cron_array[1]) || return +undef; my $days = &cron_range_populate ( 6, $cron_array[4]) || return +undef; # In theory, I should now have three array references that pass al +l checks for my $day (@$days) { for my $hour (@$hours) { for my $minute (@$ +minutes) { if ( (1440 * $day) + (60 * $hour) + $minute >= $last) { return ( "Day $day, Hour $hour, Minute $minute" ); } } } } return ( "Day $$days[0], Hour $$hours[0], Minute $$minutes[0]" ); } sub cron_range_populate { my ($max, $range) = @_; my @range = (); if ($range eq '*') { return \@{[0..$max]}; } elsif ($range !~ /[-,]/) { push @range, $range; } else { my @mini = split /,/, $range; for (@mini) { return undef if /-.*-/; # 1 dash per subsection, e.g., +"2-6-9, 24" is invalid if ( !/-/ ) { push @range, $_; } else { return undef unless /(\d+)-(\d+)/; return undef unless $1 < $2; push @range, ($1..$2); } } } return undef if $#range == -1; for (@range) { return undef unless ($_ >= 0 && $_ <= $max); } return \@range; } my $next_job = &cron_parse(time, '04 13-16 * * 01,02,03,04,05') || "ba +d input"; print "Next job kicks off : $next_job\n";

    Comments welcome.