【问题标题】:How do I run a script for 1st working day of every month in cron?如何在 cron 中为每个月的第一个工作日运行脚本?
【发布时间】:2015-02-26 07:10:27
【问题描述】:

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

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

【问题讨论】:

  • 也许您可以使用一个智能作业(程序)来检查今天是否是假期,然后如果不是假期则让该代码运行您的工作。使用 cron,您可以安排智能作业每天运行。另外,这可能很有趣:unix.com/unix-for-advanced-and-expert-users/…

标签: bash unix cron


【解决方案1】:

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

【讨论】:

  • 没有复制粘贴示例。首先,您需要为自己选择的假期定义构建或购买假期日历。然后你需要编写一个使用该日历的脚本。
【解决方案2】:

首先,运行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 每天运行上述脚本。您的command 只会在当月的第一个工作日执行。

工作原理

我们来看看脚本的核心:

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

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

  • 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

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

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

    测试"$dow" -le 5 ] 验证d 是工作日(周一至周五)。测试grep -vq "$today" /path/holidays 验证d 的日期没有出现在holidays 文件中。如果两个测试都为真,则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 就会被执行。

【讨论】:

  • 我有一个查询,这里** if [ "$dow" -le 5 ] && grep -vq "$today" /path/holidays ** 这里我们要声明假期的路径日历对吗??
  • 除此之外,我得到了一切,谢谢@John1024
  • @Shirchabayshan 只需将/path/ 替换为正确的路径即可。例如,如果假期文件是/etc/holidays,则使用:if [ "$dow" -le 5 ] && grep -vq "$today" /etc/holidays
  • 我有一个查询 @John1024 如果假设 dom=31 today=12/31/2014 if [ "$dow" -le 5 ] && grep -vq "$today" /path/holidays ( this条件为真,因为 12 月 31 日不是假期)它将进入循环。 workday=Yes nworkdays=1 here [ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command (条件为真)但我怀疑这将是第一个工作日吗?所有工作日的条件都为真......在第一个工作日之后,脚本不应运行......
  • @Shirchabayshan 每次进入循环,nworkdays增加 1nworkdays=$((nworkdays+1))。这意味着在 01/01/2014,nworkdays=1,在 01/02/2014,nworkdays=2,在 12/31/2014,nworkdays=22(假设圣诞节被标记为假期)。使用nworkdays=22,条件为假,/path/command 不会运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多