我必须将 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 在每个工作日运行你的脚本,你的脚本(或包装器)需要检查它是否是当月的第一个工作日(否则退出)。