查找在给定时间之间运行的 cron 作业

发布于 2024-09-29 18:26:05 字数 91 浏览 4 评论 0原文

是否可以找到 crontab 中在时间 X 和时间 Y 之间运行的所有条目,而不必自己解析 cron 时间条目?我主要关心时间小时和分钟,而不关心其他 3 个时间字段。

Is it possible to find all entries in a crontab that run between time X and time Y without having to parse the cron time entries myself? I'm mainly concerned with time hour and minute, not so much the other 3 time fields.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

剑心龙吟 2024-10-06 18:26:05

一切皆有可能,但你必须自己解析 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 或其他东西来做。

Anything is possible but you will have to parse crontab yourself.

There are no simple answers, but just because I can here's a partial solution in 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

Call like

cron_between 09:00 16:59

This certainly won't work for complex time specifications (e.g. */2) and only reports on the first part of the command. All of this can be corrected, but probably you'd be better off doing it in perl or something.

荒岛晴空 2024-10-06 18:26:05

由于如果不解析 cron 这似乎是不可能的,所以我决定自己用 perl 编写它:
(不知道为什么格式是fubar)


#!/usr/bin/perl -w
use strict;
use Set::CrossProduct;

我的$开始; 我的$结束;

if($ARGV[0] && $ARGV[0] =~ /before/i){ $开始= 0; $end = $ARGV[1];
} elsif($ARGV[0] && $ARGV[0] =~ /after/i){ $结束= 2400; $开始=$ARGV[1]; } 别的{ $开始=$ARGV[0]; $end = $ARGV[1]; }

if(!define($begin) || !define($end)){ print STDERR "无效参数\n"; 1号出口; 我

的@crontab = `crontab -l`;

foreach 我的 $cronjob (@crontab){ 咀嚼 $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
}
}

}

子展开范围{

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;

}

Since this doesn't seem possible without parsing cron, I decided to write it myself in perl:
(not sure why the formatting is 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;

}

九局 2024-10-06 18:26:05

您可以将 crontab 文件复制并粘贴到 Excel 中,然后创建一些函数来执行此操作。由于时间字段始终位于同一位置,因此 Excel 中的列将对应于执行该命令的时间范围。

您必须编写公式,以便考虑单个整数值和重复值(例如 10 与 */10)。

如果您的 crobtab 文件更改很多并且有很多条目,那么您可能可以编写一个 php 脚本来快速解析此信息。

You could copy and paste the crontab file into Excel and then create a few functions that do this. Since the time fields are always in the same place, your columns in Excel would correspond to the timeframe in which that command is executed.

You'll have to write your formula so that is accounts for single integer values and repeating values (like 10 versus */10).

If your crobtab file changes a lot and you have many entries, then you could probably write a php script to parse this information pretty quickly.

九歌凝 2024-10-06 18:26:05

您可以使用 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

You can use the Ruby 1.8.7 gem "crontab-parser" to parse a crontab, and then iterate through each minute between the two timestamps, calling should_run? on every crontab entry:

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

So, if you have a crontab.txt that looks like this:

*   *   *   *   *   foo
18  15  *   *   *   bar

Then call the script with output from date or similar and a file containing a crontab:

ruby cron_report.rb "Sat Mar 3 02:07:32 UTC 2012" "Sat Mar 3 02:21:32 UTC 2012" crontab.txt

You'll get output like this:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文