Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

One of those crontabs 1

Status
Not open for further replies.

columb

IS-IT--Management
Feb 5, 2004
1,231
EU
I had to sort out which cron jobs were running during a defined period (04:00 - 06:00 on Monday morning) which should be easy but it wasn't. A co-worker gave me a bit of code which I messed around with and this is the result.

It should work on any system where 'crontab -l [<user>]' is valid and which has perl installed.

It does very little data vetting and is a little short on comments but, as it merely reads from crontab -l and writes to stdout it should be harmless.

The print_usage subroutine says it all.

Code:
#!/usr/bin/perl -w
use strict;
use Getopt::Std;

sub print_usage
  {
  print @_;
  print "Usage $0 [-m minute] [-h hour] [-d day] [-u user]
	hour minute and day can be either numeric or nn-nn
        example
        $0 -d2 -m30-59 -h16 
        will show all root cron jobs timed between 16:30 and 16:59 inc
        on Wednesday\n";
  exit 1;
  }

my %opts;
getopts ( 'h:d:m:u:', \%opts );
my ( @min_vals, @max_vals );
my @long_days = qw ( Mon Tue Wed Thu Fri Sat Sun );

sub parse_entry
  {
  my ( $arref, $data, $type ) = @_;
  my ($min, $max);
  $min = $min_vals[$type]; $max = $max_vals[$type];
  $data =~ /^\d+$/ and do
    {
    ( $data >= $min ) && ( $data <= $max ) and (push @$arref, $data); 
    return;
    };
  $data =~ /^(\d+)-(\d+)$/ and do
    {
    $min = ( $1 > $min ) ? $1 : $min;
    $max = ( $1 < $max ) ? $1 : $max;
    };
  $max or return;
  while ( $min <= $max )
    { push @$arref, $min; $min++; }
  }

$opts{'d'} and do
  {{
  $opts{'d'} =~ /^\d+$/ and 
    $min_vals[0] = $opts{'d'}, $max_vals[0] = $opts{'d'}, last;
  $opts{'d'} =~/^(\d+)-(\d+)$/ and 
    $min_vals[0] = $1, $max_vals[0] = $2, last;
  print_usage "Invalid day format";
  }}
or $min_vals[0] = 0, $max_vals[0] = 6;
$opts{'h'} and do
  {{
  $opts{'h'} =~ /^\d+$/ and 
    $min_vals[1] = $opts{'h'}, $max_vals[1] = $opts{'h'}, last;
  $opts{'h'} =~/^(\d+)-(\d+)$/ and 
    $min_vals[1] = $1, $max_vals[1] = $2, last;
  print_usage "Invalid hour format";
  }}
or $min_vals[1] = 0, $max_vals[1] = 23;
$opts{'m'} and do
  {{
  $opts{'m'} =~ /^\d+$/ and 
    $min_vals[2] = $opts{'m'}, $max_vals[2] = $opts{'m'}, last;
  $opts{'m'} =~/^(\d+)-(\d+)$/ 
    and $min_vals[2] = $1, $max_vals[2] = $2, last;
  print_usage "Invalid min format";
  }}
or $min_vals[2] = 0, $max_vals[2] = 59;

my $user = $opts{'u'} ? $opts{'u'} : "";

my %commands;

foreach ( `crontab -l $user` )
  {
  /^\s*#/ and next;
  my ( @mins, @hours, @days );
  my ( $minute, $hour, undef, undef, $day, @cmd ) = split / +/;
  parse_entry ( \@mins, $minute, 2 );
  parse_entry ( \@hours, $hour, 1 );
  parse_entry ( \@days, $day, 0 );
  foreach my $d ( @days )
    {
    exists $commands{$d} or $commands{$d} = {};
    foreach my $h ( @hours )
      {
      exists $commands{$d}{$h} or $commands{$d}{$h} = {};
      foreach my $m ( @mins )
        {
        exists $commands{$d}{$h}{$m} or $commands{$d}{$h}{$m} = [];
        push @{$commands{$d}{$h}{$m}}, join ' ', @cmd;
        }
      }
    }
  }

foreach my $d ( sort { $a <=> $b }keys %commands )
  {
  foreach my $h ( sort { $a <=> $b } keys %{$commands{$d}} )
    {
    foreach my $m ( sort { $a <=> $b } keys %{$commands{$d}{$h}} )
      {
      foreach ( @{$commands{$d}{$h}{$m}} )
        { printf "%s %2.2d:%2.2d %s", $long_days[$d], $h, $m, $_; }
      }
    }
  }

Ceci n'est pas une signature
Columb Healy
 
Pride comes before a fall dept :~/
I was so keen to post my new code I skimped on the testing with inevitable results. Here's the MkII which deals with n,n,n,n and n-n correctly
Code:
#!/usr/bin/perl -w
use strict;
use Getopt::Std;

sub print_usage
  {
  print @_;
  print "Usage $0 [-m minute] [-h hour] [-d day] [-u user]
	hour minute and day can be either numeric or nn-nn
        example
        $0 -d2 -m30-59 -h16 
        will show all root cron jobs timed between 16:30 and 16:59 inc
        on Wednesday\n";
  exit 1;
  }

my %opts;
getopts ( 'h:d:m:u:', \%opts );
my ( @min_vals, @max_vals );
my @long_days = qw ( Mon Tue Wed Thu Fri Sat Sun );

sub parse_entry
  {
  my ( $arref, $data, $type ) = @_;
  my ($min, $max);
  $min = $min_vals[$type]; $max = $max_vals[$type];
  $data =~ /^\d+$/ and do
    {
    ( $data >= $min ) && ( $data <= $max ) and (push @$arref, $data); 
    return;
    };
  $data =~ /^[\d,]+$/ and do
    {
    foreach ( split /,/, $data )
      {( $_ >= $min ) && ( $_ <= $max ) and (push @$arref, $_);}
    return;
    };
  $data =~ /^(\d+)-(\d+)$/ and do
    {
    $min = ( $1 > $min ) ? $1 : $min;
    $max = ( $2 < $max ) ? $2 : $max;
    };
  $max or return;
  while ( $min <= $max )
    { push @$arref, $min; $min++; }
  }

$opts{'d'} and do
  {{
  $opts{'d'} =~ /^\d+$/ and 
    $min_vals[0] = $opts{'d'}, $max_vals[0] = $opts{'d'}, last;
  $opts{'d'} =~/^(\d+)-(\d+)$/ and 
    $min_vals[0] = $1, $max_vals[0] = $2, last;
  print_usage "Invalid day format";
  }}
or $min_vals[0] = 0, $max_vals[0] = 6;
$opts{'h'} and do
  {{
  $opts{'h'} =~ /^\d+$/ and 
    $min_vals[1] = $opts{'h'}, $max_vals[1] = $opts{'h'}, last;
  $opts{'h'} =~/^(\d+)-(\d+)$/ and 
    $min_vals[1] = $1, $max_vals[1] = $2, last;
  print_usage "Invalid hour format";
  }}
or $min_vals[1] = 0, $max_vals[1] = 23;
$opts{'m'} and do
  {{
  $opts{'m'} =~ /^\d+$/ and 
    $min_vals[2] = $opts{'m'}, $max_vals[2] = $opts{'m'}, last;
  $opts{'m'} =~/^(\d+)-(\d+)$/ 
    and $min_vals[2] = $1, $max_vals[2] = $2, last;
  print_usage "Invalid min format";
  }}
or $min_vals[2] = 0, $max_vals[2] = 59;

my $user = $opts{'u'} ? $opts{'u'} : "";

my %commands;

foreach ( `crontab -l $user` )
  {
  /^\s*#/ and next;
  my ( @mins, @hours, @days );
  my ( $minute, $hour, undef, undef, $day, @cmd ) = split / +/;
  parse_entry ( \@mins, $minute, 2 );
  parse_entry ( \@hours, $hour, 1 );
  parse_entry ( \@days, $day, 0 );
  foreach my $d ( @days )
    {
    exists $commands{$d} or $commands{$d} = {};
    foreach my $h ( @hours )
      {
      exists $commands{$d}{$h} or $commands{$d}{$h} = {};
      foreach my $m ( @mins )
        {
        exists $commands{$d}{$h}{$m} or $commands{$d}{$h}{$m} = [];
        push @{$commands{$d}{$h}{$m}}, join ' ', @cmd;
        }
      }
    }
  }

foreach my $d ( sort { $a <=> $b }keys %commands )
  {
  foreach my $h ( sort { $a <=> $b } keys %{$commands{$d}} )
    {
    foreach my $m ( sort { $a <=> $b } keys %{$commands{$d}{$h}} )
      {
      foreach ( @{$commands{$d}{$h}{$m}} )
        { printf "%s %2.2d:%2.2d %s", $long_days[$d], $h, $m, $_; }
      }
    }
  }

Ceci n'est pas une signature
Columb Healy
 
Columb,

Very nice. In an environment like mine with hundreds of Oracle servers this is most useful.

Thanks
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top