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

Bash 如何在cron中为每个月的第一个工作日运行脚本?,bash,unix,cron,Bash,Unix,Cron,我必须将cronjob设置为每个月的第一个工作日,这意味着脚本应该在每个月的第一个工作日运行 如果假设第一个工作日是假日,那么脚本应该在第二个工作日运行。 例如:2015年1月1日是假日,那么脚本应该在2015年1月2日运行。Cron没有假日日历的概念,也没有添加此类概念的挂钩。悲伤,但真实。您将需要实现您自己的假日日历(或者很明显,找到一个,但不是在cron中)。然后,您可以将cron设置为在每个工作日运行脚本,您的脚本(或包装器)将需要检查它是否是当前月份的第一个工作日(否则退出)。首先,运

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

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

Cron没有假日日历的概念,也没有添加此类概念的挂钩。悲伤,但真实。您将需要实现您自己的假日日历(或者很明显,找到一个,但不是在cron中)。然后,您可以将cron设置为在每个工作日运行脚本,您的脚本(或包装器)将需要检查它是否是当前月份的第一个工作日(否则退出)。

首先,运行
date
命令:

$ date '+%x'
12/29/2014
%x
告诉date以当前区域设置的格式显示今天的日期。使用完全相同的格式,将假日列表放入名为
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每天运行上面的脚本。您的
命令将仅在每月的第一个工作日执行

工作原理 让我们看一下脚本的核心:

  • 表示d,单位为美元(seq 1$dom);执行

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

  • today=$(日期-d“$year-$month-$d”'+%x')#区域设置的日期表示法(例如1999年12月31日)

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

  • dow=$(日期-d“$year-$month-$d”+%u”)#一周中的一天:1-7天,其中1=周一,7=周日

    这将
    d
    天的
    dow
    设置为一周中的某一天,其中1=周一,7=周日

  • if[“$dow”-le 5]&grep-vq“$today”/path/假日

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

  • 然后workday=Yes;nworkdays=$((nworkdays+1))

    then
    子句将
    workday
    设置为
    Yes
    ,并增加本月迄今为止的工作日数:
    nworkdays

  • else workday=

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

  • fi

    fi
    表示
    if
    语句结束

  • done

    done
    表示
    for
    循环的结束

  • [“$workday”]&&&[“$nworkdays”-等式1]&&&/path/command

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


也许你可以使用一个智能作业(程序)来检查今天是否是假日,如果不是假日,则让代码运行你的作业。使用cron,您可以安排智能作业每天运行。此外,这可能很有趣:没有复制粘贴示例。首先,您需要为自己选择的假日定义构建或购买假日日历。然后,您需要编写一个使用该日历的脚本。我有一个查询,这里**if[“$dow”-le 5]&&grep-vq“$today”/path/holidays**我们必须在这里声明假日日历的路径正确??除此之外,我得到了所有信息,谢谢@John1024@Shirchabayshan只要用正确的路径替换
/path/
。例如,如果假日文件是
/etc/holidays
,那么使用:
如果[“$dow”-le5]&&grep-vq“$today”/etc/holidays
我有一个查询@John1024,假设dom=31 today=12/31/2014,如果[“$dow”-le5]&&grep-vq“$today”/path/holidays(自12月31日不是假日以来,该条件将为真)它将进入循环。workday=Yes nworkdays=1此处[“$workday”]&&&[“$nworkdays”-eq 1]&&&&/path/command(条件为真),但我怀疑这怎么会是第一个工作日?该条件在所有工作日内均为真。。。在第一个工作日之后,脚本不应在每次进入循环时运行…@shirchabaysan,
nworkdays
递增1:
nworkdays=$((nworkdays+1))
。这意味着在2014年1月1日,
nworkdays=1
、2014年2月1日,
nworkdays=2
、2014年12月31日,
nworkdays=22
(假设圣诞节被标记为假日)。如果
nworkdays=22
,则条件将为false,并且
/path/command
将不会运行。