如何在 cron 中为每个月的第一个工作日运行脚本



我必须将 cronjob 设置为每月的第一个工作日,这意味着脚本应该在每个月的第一个工作日运行

如果假设第一个工作日是假期,那么脚本应该在第二个工作日运行。例如:2015 年 1 月 1 日是假期,那么脚本应该在 2015 年 1 月 2 日运行。

首先,运行 date 命令:

$ date '+%x'
12/29/2014

%x告诉日期以当前区域设置的格式显示今天的日期。 使用完全相同的格式,将假期列表放在名为 holidays 的文件中。 例如:

$ cat holidays
01/01/2015
07/04/2015

接下来,创建以下 shell 脚本:

#!/bin/sh
dom=$(date '+%d') # 01-31, day of month
year=$(date '+%Y') # four-digit year
month=$(date '+%m') # two-digit month
nworkdays=0
for d in $(seq 1 $dom)
do
    today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)
    dow=$(date -d "$year-$month-$d" '+%u')   # day of week: 1-7 with 1=Monday, 7=Sunday
    if [ "$dow" -le 5 ]  && grep -vq "$today" /path/holidays
    then
        workday=Yes
        nworkdays=$((nworkdays+1))
    else
        workday=
    fi
done
[ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command

其中/path/command替换为要在当月第一个工作日运行的任何命令。 此外,将/path/holidays替换为 holidays 文件的正确路径。

最后,告诉 cron 每天运行上面的脚本。 您的command只会在当月的第一个工作日执行。

工作原理

我们来看看剧本的核心:

  • for d in $(seq 1 $dom); do

    这将启动一个循环,运行从 1 到当前日期的变量d

  • today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)

    这会today设置为本月和今年的日期d的日期字符串。

  • dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday

    这会将第 d 天的dow设置为星期几,其中 1 = 星期一,7 = 星期日。

  • if [ "$dow" -le 5 ] && grep -vq "$today" /path/holidays

    测试"$dow" -le 5 ]验证d天是工作日(周一至周五)。测试grep -vq "$today" /path/holidays验证日期d 的日期未出现在holidays文件中。 如果两个测试都为 true,则第 d 天是一个工作日,执行 then 子句:

  • then workday=Yes; nworkdays=$((nworkdays+1))

    then 条款将workday设置为 Yes,并增加了本月到目前为止的工作日数:nworkdays

  • else workday=

    else 子句将workday设置回空字符串。

  • fi

    fi表示if语句结束。

  • done

    done表示for循环的结束。

  • [ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command

    for声明中的最后一个循环是今天的日期。 因此,如果在循环结束后workday=Yes,那么今天就是工作日。 此外,如果nworkdays=1,那么今天是该月的第一个工作日。 如果这两个条件都为真,则执行命令/path/command

Cron 没有节日日历的概念,也没有任何钩子来添加这样的概念。 悲伤,但真实。 您将需要实现自己的假期日历(或者显然找到一个,但不是在 cron 中)。 然后你可以设置 cron 在每个工作日运行你的脚本,你的脚本(或包装器)需要检查它是否是当月的第一个工作日(否则退出)。

最新更新