#!/usr/local/bin/perl -w # showcrontab # # Displays the contents of a crontab file in a human readable form. # Copyright (C) November 1997, William R. Ward . # # Copying and distribution permitted under GNU public license, or the # Perl "Artistic License". See GNU and Perl documentation for more info. require 5.003; # minimum Perl version use strict; # strict syntax checking use Text::Wrap; # use wrap function # Set the margin for wrapping $Text::Wrap::columns = 72; # Text for days of the week my @weekdays = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); # If no command line arguments given, use output of 'crontab -l' unshift (@ARGV, "crontab -l |") unless @ARGV; # For each line of the input, parse and display. while (<>) { chomp; # remove trailing newline next if /^#/; # skip comments # The crontab format is six fields separated by spaces. The first # five are the minute, hour, day of month, day of year, and day of # week, respectively. Each is either '*' which means 'all', or a # list of ranges of numbers. Example values include '6', '1,3,7', # '20-40', '1-5,7', etc. No space may be included in any field # except for the sixth, which is the command to run. my ($min, $hour, $mday, $yday, $wday, $cmd) = split(/\s+/, $_, 6); # Display first the command that is to be run. print wrap('', "\t\t ", "Run the command: $cmd\n"); # Display the time. If the hour is given... if ($hour ne '*') { # ...and the minute is given... if ($min ne '*') { # Split the hours and minutes into lists of times using # str2list() and display a list of times such as '9:00 am, 5:30 pm' my @hours = str2list($hour); my @mins = str2list($min); my ($i, $j, @times); foreach $i (@hours) { # convert $i (the hour cursor) to am/pm style my $ampm = ($i >= 12 ? 'pm' : 'am'); $i -= 12 if $i >= 12; $i = 12 if $i == 0; foreach $j (@mins) { push (@times, sprintf('%d:%02d %s', $i, $j, $ampm)); } } print wrap('', " ", " At ".list2str(@times)." each day\n"); } # Hour given but minute not given. else { print wrap('', " ", " Every minute during the ". convertnum($hour)." hour each day\n") if $hour ne '*'; } } # Hour is not given but minute is... elsif ($min ne '*') { print wrap('', " ", " At the ".convertnum($min)." minute past each hour\n"); } # Display day of month info if given. print wrap('', " ", " On the ".convertnum($mday)." day of the month\n") if $mday ne '*'; # Display day of week info if given. Converts the number into the # name of the day(s) given. if ($wday ne '*') { my $msg = convertnum($wday); $msg =~ s/(\d)(st|nd|rd|th)/$weekdays[$1]/g; print wrap('', " ", " On $msg\n"); } # Display day of year info if given. print wrap('', " ", " On the ".convertnum($yday)." day of the year\n") if $yday ne '*'; # Blank line after this entry. print "\n"; } # Subroutine str2list takes a string which contains a single item or a # comma-separated list of items, where 'item' is either a number or a # hyphen-separated range of numbers. It then returns an array of # numbers represented by the list/ranges given. Input is scalar; # output is list. sub str2list { my ($nums) = @_; my (@numbers); my @list = split(/,/, $nums); foreach (@list) { if (/(\d+)-(\d+)/) { push (@numbers, $1 .. $2); } else { push (@numbers, $_); } } return @numbers; } # Subroutine convertnum converts entry such as '1,12,23-25' into a # string such as '1st, 12th, and 23rd through 25th'. Input and output # are both scalars. sub convertnum { my ($str) = @_; my @numbers = split(/,/, $str); my ($num, @retval); foreach $num (@numbers) { if ($num =~ /(\d+)-(\d+)/) { push (@retval, num2word($1).' through '.num2word($2)); } else { push (@retval, num2word($num)); } } return list2str(@retval); } # Subroutine num2word converts a number into a word by adding 'st', # 'nd', 'rd', or 'th' as appropriate. Input and output are both # scalars. sub num2word { my ($num) = @_; $num += 0; # ensure value is numeric. my $lastdigit = substr($num, length($num)-1, 1); if ($lastdigit == 1) { $num .= 'st'; } elsif ($lastdigit == 2) { $num .= 'nd'; } elsif ($lastdigit == 3) { $num .= 'rd'; } else { $num .= 'th'; } return $num; } # Converts an array into a string by adding commas and 'ands' where # appropriate. Uses the 'terminal comma' syntax, e.g. 'foo, bar, and # baz' as opposed to 'foo, bar and baz'. For two elements, no comma # is used. Input is array, output is scalar. sub list2str { my (@list) = @_; if (@list == 1) # single element, just return it. { return $list[0]; } elsif (@list == 2) # two elements, return '1 and 2' { return join(' and ', @list); } else # three or more elements, return '1, 2, and 3' { my $last = pop @list; return join(', ', @list).", and $last"; } }