是否可以在crontab中找到在时间X和时间Y之间运行的所有条目,而不必自己解析cron时间条目?我主要关注时间和时间,而不是其他3个时间段。
答案 0 :(得分:3)
一切皆有可能,但你必须自己解析crontab。
没有简单的答案,只是因为我可以在bash中找到部分解决方案。
#!/bin/bash
start="${1-0:0}"
end="${2-0:0}"
start_hour=$(cut -d: -f1 <<<"$start")
end_hour=$(cut -d: -f1 <<<"$end")
start_min=$(cut -d: -f2 <<<"$start")
end_min=$(cut -d: -f2 <<<"$end")
# leading zeroes would be bad
let start_hour=10#${start_hour}
let end_hour=10#${end_hour}
let start_min=10#${start_min}
let end_min=10#${end_min}
cat /etc/crontab | \
grep -v ^\# | \
grep -E -v '^([a-zA-Z]+)' | \
awk '{print $1, $2, $7}' | \
while read line ; do
if [ ! -z "$line" ] ; then
h=$(cut -d' ' -f2 <<<"$line")
m=$(cut -d' ' -f1 <<<"$line")
cmd=$(cut -d' ' -f3- <<<"$line")
if [ "$h" = '*' ] || ( [ $h -ge $start_hour ] && [ $h -le $end_hour ] ) ; then
if [ "$m" = '*' ] || ( [ $m -ge $start_min ] && [ $m -le $end_min ] ) ; then
echo $cmd
fi
fi
fi
done
像
一样打电话cron_between 09:00 16:59
这肯定不适用于复杂的时间规范(例如* / 2),只报告命令的第一部分。所有这一切都可以得到纠正,但是你可能会更好地在perl或其它东西上做这件事。
答案 1 :(得分:2)
由于在没有解析cron的情况下这似乎不可能,我决定自己在perl中写它:
(不确定为什么格式化为fubar)
#!/usr/bin/perl -w
use strict;
use Set::CrossProduct;
my $begin;
my $end;
if($ARGV[0] && $ARGV[0] =~ /before/i){
$begin = 0;
$end = $ARGV[1];
}
elsif($ARGV[0] && $ARGV[0] =~ /after/i){
$end = 2400;
$begin = $ARGV[1];
}
else{
$begin = $ARGV[0];
$end = $ARGV[1];
}
if(!defined($begin) || !defined($end)){
print STDERR "Invalid Arguments\n";
exit 1;
}
my @crontab = `crontab -l`;
foreach my $cronjob (@crontab){
chomp $cronjob;
next if $cronjob =~ /^ *\#/ ||$cronjob =~ /^ *$/ ;
#print "in: $cronjob\n";
my ($min,$hour,$day_of_month,$month,$day_of_week, @cmd) = split(/ /, $cronjob);
my @mins = expandRange($min,0,59);
my @hours = expandRange($hour,0,23);
my $cp = Set::CrossProduct->new([\@hours,\@mins]);
my $combos = $cp->combinations();
foreach my $time ( map { $_->[0]*100 + $_->[1] } @$combos){
if($time >= $begin && $time <= $end){
print $cronjob,"\n";
last; #don't print the job n times, just once
}
}
}
sub expandRange{
my ($in,$begin,$end) = @_;
#print "in: ($in)[$begin:$end]\n";
my @range;
my @vals = split(/,/,$in);
foreach my $val (@vals){
my $mult = 1;
if($val =~ /\/(.+)$/){
$mult = $1;
$val =~ s/\/(.+)//;
}
if($in =~ /\*/){
@range = grep { $_ % $mult == 0 && $_ >= $begin && $_ <= $end } $begin..$end;
}
elsif($val =~ /[\-:]/){
my ($first, $last) = split(/[\-:]/,$val);
push(@range, grep { $_ % $mult == 0 && $_ >= $begin && $_ <= $end } $first..$last);
}
elsif($val >= $begin && $val <= $end) {
push(@range, $val);
}
}
my %unique;
@unique{@range} = 1;
return sort keys %unique;
}
答案 2 :(得分:1)
您可以将crontab文件复制并粘贴到Excel中,然后创建一些执行此操作的函数。由于时间字段始终位于同一位置,因此Excel中的列将对应于执行该命令的时间范围。
您必须编写公式,以便考虑单个整数值和重复值(例如10对* / 10)。
如果您的crobtab文件发生了很大变化并且您有很多条目,那么您可能会编写一个php脚本来快速解析这些信息。
答案 3 :(得分:1)
您可以使用Ruby 1.8.7 gem "crontab-parser"来解析crontab,然后在两个时间戳之间迭代每一分钟,在每个crontab条目上调用should_run?
:
require 'rubygems'
require 'crontab-parser'
start_time = Time.parse(ARGV[0])
end_time = Time.parse(ARGV[1])
# CrontabParser barfs on env variable setting in a crontab, so just skip them
cron_data = File.readlines(ARGV[2]).select {|line| line =~ /^[0-9*]/}
cron = CrontabParser.new(cron_data.join("\n"))
(start_time..end_time).each do |timestamp|
next unless timestamp.sec.to_i == 0
cron.each do |cron_entry|
if cron_entry.should_run?(timestamp)
puts "#{timestamp}\t#{cron_entry.cmd}"
end
end
end
所以,如果你的crontab.txt
看起来像这样:
* * * * * foo
18 15 * * * bar
然后使用date
或类似的输出以及包含crontab的文件调用脚本:
ruby cron_report.rb "Sat Mar 3 02:07:32 UTC 2012" "Sat Mar 3 02:21:32 UTC 2012" crontab.txt
你会得到这样的输出:
Sat Mar 03 15:17:00 UTC 2012 * * * * * foo
Sat Mar 03 15:18:00 UTC 2012 * * * * * foo
Sat Mar 03 15:18:00 UTC 2012 18 15 * * * bar
Sat Mar 03 15:19:00 UTC 2012 * * * * * foo
Sat Mar 03 15:20:00 UTC 2012 * * * * * foo