如何配置满足每月20日且周一、间隔20天执行的Cron Job?
解决你的Cron Job配置难题
看起来你遇到了一个纯Cron没法直接搞定的需求——毕竟Cron是基于静态时间规则的,没法追踪上次执行的时间来计算动态间隔。不过结合脚本的话,我们可以完美实现你的两个要求:每月20日且为周一执行,同时两次执行的周一之间间隔20天。
核心问题分析
首先得明确两个关键限制:
- Cron的
日和周字段是逻辑或的关系,比如你写0 2 20 * 1,它会在每月20日或者每周一执行,完全不符合你“20日且周一”的要求; - Cron没法记录上次执行的时间,所以“间隔20天的周一”这种动态规则,纯Cron表达式根本实现不了。
解决方案:脚本+Cron组合
我们可以写一个脚本,让它每天自动检查两个触发条件,满足任意一个就执行任务,同时记录上次执行的日期来追踪间隔。
步骤1:创建任务脚本
新建一个脚本文件(比如/usr/local/bin/scheduled_task.sh),内容如下:
#!/bin/bash # 用来记录上次执行日期的文件,路径可以根据自己的习惯调整 LAST_RUN_LOG="/var/log/last_task_run.txt" TODAY=$(date +%Y-%m-%d) # 条件1:今天是每月20日且为周一(%u表示周一=1,周日=7) if [ $(date +%d) -eq 20 ] && [ $(date +%u) -eq 1 ]; then echo "[$TODAY] 触发条件:每月20日且周一" # 这里替换成你实际要执行的任务命令 # /path/to/your/actual/command # 更新上次执行记录 echo "$TODAY" > "$LAST_RUN_LOG" exit 0 fi # 条件2:距离上次执行刚好20天,且今天是周一 if [ -f "$LAST_RUN_LOG" ]; then LAST_RUN_DATE=$(cat "$LAST_RUN_LOG") # 计算两次日期的间隔天数(基于时间戳换算) DIFF_DAYS=$(( ( $(date -d "$TODAY" +%s) - $(date -d "$LAST_RUN_DATE" +%s) ) / 86400 )) if [ $DIFF_DAYS -eq 20 ] && [ $(date +%u) -eq 1 ]; then echo "[$TODAY] 触发条件:间隔20天且周一" # 替换成你的任务命令 # /path/to/your/actual/command # 更新上次执行记录 echo "$TODAY" > "$LAST_RUN_LOG" exit 0 fi fi # 两个条件都不满足,直接退出 exit 1
步骤2:给脚本添加执行权限
chmod +x /usr/local/bin/scheduled_task.sh
步骤3:配置Cron每天触发脚本
打开Cron编辑器:
crontab -e
添加一行(这里设置每天凌晨2点检查一次,时间可以根据你的需求调整):
0 2 * * * /usr/local/bin/scheduled_task.sh
额外说明
- 如果你用的是macOS(BSD date命令),日期计算的语法需要调整:把
date -d "$TODAY" +%s改成date -j -f "%Y-%m-%d" "$TODAY" +%s,LAST_RUN_DATE的计算部分也要做同样修改; - 可以把脚本里的echo输出追加到日志文件,方便排查问题,比如改成
echo "[$TODAY] 触发条件..." >> /var/log/task_execution.log; - 第一次执行前,如果你想从某个特定日期开始计算间隔,可以手动创建
LAST_RUN_LOG文件并写入起始日期,比如echo "2024-10-12" > /var/log/last_task_run.txt。
这样配置后,你的任务就会在两种场景下自动执行:
- 每月20日恰好是周一的时候;
- 距离上次执行刚好20天,且当天是周一的时候(比如你举例的10月12日执行后,11月2日会自动触发)。
内容的提问来源于stack exchange,提问作者Abhishek Singh




