昔に書いたPerlスクリプトです。PATHの通っている /usr/local/bin/ に置いてコマンドとして使用しています。
cron daemonのスケジューリングを確認したい時に使います。
cronデーモンとは?
Unix系のOSには、cronというデーモン(サービス)があります。時間とコマンドを指定しておくと、その時間にコマンドを実行してくれる仕組みになっています。Windowsだと「タスク スケジューラ」に該当するものだと思います。が、cron daemonのトリガーは時間だけなので、「タスク スケジューラ」よりももっとシンプルです。
cronデーモンに仕事を依頼しておく方法は?
テキストファイルに記述します。Linuxだとcrontab -eで編集できるのですが、他システムがどうだったかはうろ覚えです。man crontabで調べればすぐに判る事なので、覚える必要無しです。
書き方はというと、例えば「毎週土曜日の5時にバックアップを実行」と設定したい場合には以下のような感じで記述します。
[crontab]の記述例
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
0 5 * * 6 /home/user1/job/differential_backup.sh
何かしらサーバーで作業する時は、作業中に変な処理が実行されない事、もしくは作業にあたりデーモンを停止しても問題ない事を確認する為に、cronの実行予定を確認するのですが、このファイルが読みづらくて、瞬時に読解する事ができません。なので、読み易く翻訳して表示するスクリプトを書いていました。当時はSolaris等のUnixやLinuxで使っていました。
スクリプトの実行例
CentOS Stream 9
[root@hostname ~]# cronscj --help
usage: cronscj [YYYY/mm/dd]
[root@hostname ~]#
[root@hostname ~]# cronscj
2022/10/15(Sat) 00:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 01:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 02:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 03:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 04:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 05:00 user1 /home/user1/job/differential_backup.sh
2022/10/15(Sat) 05:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 06:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 07:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 08:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 09:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 10:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 11:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 12:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 13:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 14:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 15:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 16:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 17:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 18:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 19:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 20:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 21:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 22:01 root run-parts /etc/cron.hourly
2022/10/15(Sat) 23:01 root run-parts /etc/cron.hourly
[root@hostname ~]#
Perlスクリプト
[cronscj]
#!/usr/bin/perl -w
################################################################################
## CRONSCJ -- 指定された日付のCRONスケジュールをリストアップする
##
## - Author: tomyama Dec 2005
## - Version: 2 2005/12: Perlで書き直した
## - Version: 1 2002/06: CSHELL + awk でLinux用に作成
## - Only for personal use !
################################################################################use strict ;
use File::Basename ;
use Time::Local qw{timelocal} ;exit &pl_main (@ARGV) ;
sub pl_main (@) {
&initialize (@_) ;
&parse_arg (@_) ;&mk_tbl_user () ;
&get_cronentry () ;
foreach my $i (keys (%main::user)) {
&get_cronentry ("$i") ;
}foreach my $myindex (sort (keys (%main::cron))) {
my ($mydate, $myuid) = (split ("_", $myindex))[0, 1] ;
my $myuser = getpwuid ($myuid) ;
printf ("$mydate %-8s $main::cron{$myindex}\n", $myuser) ;
}return 0 ;
}sub initialize (@) {
$main::appname = basename ($0) ;@main::wday = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat') ;
($main::trgtYear, $main::trgtMonth, $main::trgtDay, $main::trgtWeek) =
(localtime (time ()))[5, 4, 3, 6] ;
$main::trgtYear += 1900 ;
$main::trgtMonth += 1 ;return 0 ;
}sub parse_arg {
my @val = @_ ;## 引数分のループを回す
while ($#val != -1) {
my $myparam = shift (@val) ;if ($myparam =~ m/^(?:20[0-9]{2}[\-\/\.])?[0-9]{1,2}[\-\/\.][0-9]{1,2}$/o) {
my @myarg = split (/[\-\/\.]/, $myparam) ;
if ($#myarg < 1 || 2 < $#myarg) {
warn ("$myparam: unknown option\n") ;
&usage () ;
exit (1) ;
}
my $myYear = shift (@myarg) - 1900 if ($#myarg == 2) ;
$myYear = $main::trgtYear if (! defined ($myYear)) ;
my $myMonth = shift (@myarg) - 1 ;
if ($myMonth < 0 || 11 < $myMonth) {
warn ("${main::appname}: $myMonth: out of range 0..11\n") ;
exit (1) ;
}
my $myDay = shift (@myarg) ;
if ($myDay < 1 || 31 < $myDay) {
warn ("${main::appname}: $myDay: out of range 1..31\n") ;
exit (1) ;
}
($main::trgtYear, $main::trgtMonth,
$main::trgtDay, $main::trgtWeek) =
(localtime (timelocal (0, 0, 0, $myDay,
$myMonth, $myYear)))[5, 4, 3, 6] ;
$main::trgtYear += 1900 ;
$main::trgtMonth += 1 ;
} elsif ("$myparam" eq '-h' || "$myparam" eq '--help') {
&usage () ;
exit (0) ;
} else {
&usage () ;
exit (0) ;
}
}
return 0 ;
}sub mk_tbl_user {
my $passwd = '/etc/passwd' ;
die ("${main::appname}: $passwd: file not found\n") if (! -f "$passwd") ;
open (PASSWD, "<$passwd") ||
die ("${main::appname}: $passwd: can not open\n") ;
while (<PASSWD>) {
my $buff = $_ ; chomp ($buff) ;
$main::user{(split (":", $buff))[0]} = 1 ;
}
close (PASSWD) ;
return 0 ;
}sub get_cronentry ($) {
my $keyuser = shift (@_) ;
my $myCronFormat = 0 ;
$myCronFormat = 1 if (! defined ($keyuser)) ;if ($myCronFormat) {
foreach my $i ('/etc/crontab', </etc/cron.d/*>) {
&read_crontab ($myCronFormat, $i) ;
}
} else {
foreach my $i ("/var/spool/cron/crontabs/$keyuser",
"/var/spool/cron/$keyuser") {
&read_crontab ($myCronFormat, $i) ;
}
}return 0 ;
}sub read_crontab ($$) {
my $myCronFormat = shift (@_) ;
my $myCronFile = shift (@_) ;return 1 if (! -f "$myCronFile") ;
if (! -r "$myCronFile") {
warn ("${main::appname}: $myCronFile: can not readable\n") ;
return 1 ;
}my $cron_val_User = basename ($myCronFile) ;
open (CRONTABS, "<$myCronFile") ||
die ("${main::appname}: $myCronFile: can not open\n") ;
LOOP_CRONTABS: while (<CRONTABS>) {
my $buff = $_ ; chomp ($buff) ; $buff =~ s/#.*$//o ;
$buff =~ s/^\s+//o ;
$buff =~ s/\s+$//o ;
next if ("$buff" eq '') ;
next if (! ($buff =~ m/^(?:[0-9,\*\-\/]+\s+){5}/o)) ;#my @tm_val = (split (/\s+/, $buff))[0..4] ;
my @cron_val = split (/\s+/, $buff) ;my $cron_val_Minute = shift (@cron_val) ;
my $cron_val_Hour = shift (@cron_val) ;
my $cron_val_Day = shift (@cron_val) ;
my $cron_val_Month = shift (@cron_val) ;
my $cron_val_Week = shift (@cron_val) ;$cron_val_User = shift (@cron_val) if ($myCronFormat == 1) ;
my $cron_val_UID = getpwnam ($cron_val_User) ;## 曜日指定を解析
my @myaryWeekDay = &parse_tm_val ($cron_val_Week, 0, 6) ;
my $myflagWeekDay = 0 ;
LOOP_WEEKDAY: foreach my $myWeekDay (@myaryWeekDay) {
if ($myWeekDay == $main::trgtWeek) {
$myflagWeekDay = 1 ;
last LOOP_WEEKDAY ;
}
}
next if (! $myflagWeekDay) ;## 月指定を解析
my @myaryMonth = &parse_tm_val ($cron_val_Month, 1, 12) ;
my $myflagMonth = 0 ;
LOOP_MONTH: foreach my $myMonth (@myaryMonth) {
if ($myMonth == $main::trgtMonth) {
$myflagMonth = 1 ;
last LOOP_MONTH ;
}
}
next if (! $myflagMonth) ;## 日指定を解析
my @myaryDay = &parse_tm_val ($cron_val_Day, 1, 31) ;
my $myflagDay = 0 ;
LOOP_DAY: foreach my $myDay (@myaryDay) {
if ($myDay == $main::trgtDay) {
$myflagDay = 1 ;
last LOOP_DAY ;
}
}
next if (! $myflagDay) ;## 時指定を解析
my @myaryHour = &parse_tm_val ($cron_val_Hour, 0, 23) ;## 分指定を解析
my @myaryMinute = &parse_tm_val ($cron_val_Minute, 0, 59) ;#print ("CRONTAB: $myCronFile, ENTRY: $buff\n") ;
foreach my $myHour (@myaryHour) {
foreach my $myMinute (@myaryMinute) {
my $keyidx = sprintf ("%04d/%02d/%02d(%3s) %02d:%02d_%07d",
$main::trgtYear, $main::trgtMonth,
$main::trgtDay,
$main::wday[$main::trgtWeek],
$myHour, $myMinute, $cron_val_UID) ;
my $myseq = 0 ;
my $keystr = undef ;
do {
$keystr = $keyidx . '_' .
sprintf ("%07d", ++$myseq) ;
} while (defined ($main::cron{$keystr})) ;
$main::cron{$keystr} = join (" ", @cron_val) ;
#print ("TIME: $keystr, $main::cron{$keystr}\n") ;
}
}
}
close (CRONTABS) ;return 0 ;
}sub parse_tm_val ($$$) {
my $mytmstr = shift (@_) ;
my $mytmmin = shift (@_) ;
my $mytmmax = shift (@_) ;#if (! ($mytmstr =~ m/^(?:\*|(?:[0-9]+(?:-[0-9]+(?:\/[0-9]+)?)?,?)+)$/o)) {
if (! ($mytmstr =~ m!^(?:(?:\*|(?:[0-9]+(?:-[0-9]+)?))(?:/[0-9]+)?,?)+$!o)) {
die ("${main::appname}: ${mytmstr}: unknown format\n") ;
}
## 考えられるフォーマット
## */10
## 0,5-9,10-20/5,30
my %myhash ;
#if ($mytmstr eq '*') {
# return $mytmmin .. $mytmmax ;
#}
foreach my $myentry (split (/,/, $mytmstr)) {
my ($mytm, $mylaps) = (split (/\//, $myentry))[0, 1] ;
$mylaps = 1 if (! defined ($mylaps)) ;
my ($mytmfr, $mytmto) = (split (/-/, $mytm))[0, 1] ;
if ($mytmfr eq '*') {
$mytmfr = $mytmmin ;
$mytmto = $mytmmax ;
}
$mytmto = $mytmfr if (! defined ($mytmto)) ;
for (my $i=$mytmfr; $i<=$mytmto; $i+=$mylaps) {
last if ($i < $mytmmin || $mytmmax < $i) ;
$myhash{int ($i)} = 1 ;
}
}my @myarray ;
foreach my $i (sort { $a <=> $b } (keys (%myhash))) {
$myarray[$#myarray+1] = $i ;
}return @myarray ;
}sub usage {
warn ("usage: ${main::appname} [YYYY/mm/dd]\n") ;
return 0 ;
}