生产环境crontab需确保可维护、可排查、可收敛,关键包括:用绝对路径和显式环境变量;统一工作目录;加锁防并发;日志重定向并带时间戳;厘清时间字段逻辑;转义特殊字符。

生产环境里写 crontab,不能只图“能跑”,得考虑可维护、可排查、可收敛。真正出问题的,往往不是语法写错,而是环境没对、路径不对、并发失控、日志缺失。
绝对路径 + 显式环境变量
crontab 不继承你的 shell 环境,PATH 极简(通常只有 /usr/bin:/bin),所以:
- 命令必须用绝对路径:用 /usr/bin/python3,别写 python3
- 脚本也必须用绝对路径:/opt/clawdbot/scripts/daily-report.sh,别写 ./daily-report.sh
- 在 crontab 文件顶部加一行声明环境:PATH=/usr/local/bin:/usr/bin:/bin
- 需要特定环境变量(如 HOME、OLLAMA_HOST)时,直接在命令前赋值:HOME=/home/user OLLAMA_HOST=http://localhost:11434 /usr/bin/node /opt/clawdbot/dist/index.js agent --message "daily"
工作目录与相对路径陷阱
cron 启动任务时,默认工作目录是用户家目录(/home/username),不是脚本所在目录。一旦脚本里有 ./config.yml 或 ../data/logs 这类写法,必然失败。
- 统一在命令前加 cd /full/path/to/script/dir &&
- 或者在脚本开头第一行写:cd "$(dirname "$0")"
- 更稳妥的做法:所有路径都用绝对路径,避免任何 .. 或 .
防重叠 + 锁机制
*/5 * * * * 这类写法不保证任务串行。若上次执行耗时超过 5 分钟,下次仍会准时启动,可能造成资源争抢、数据重复、API 调用超限。
- 简单锁:用 mkdir 原子性判断(比 touch + file 检查更可靠):
*/5 * * * * if mkdir /tmp/daily-report.lock 2>/dev/null; then /opt/clawdbot/scripts/daily-report.sh; rmdir /tmp/daily-report.lock; fi - 推荐封装成小工具(如 run-one),或改用 systemd timer 替代复杂调度
- 关键任务建议加超时控制:timeout 300 /opt/clawdbot/scripts/daily-report.sh(5 分钟强制终止)
日志重定向 + 错误捕获
不重定向,stdout/stderr 默认发邮件——生产环境几乎没人收 cron 邮件,等于静默失败。
- 标准写法:2>&1 >> /var/log/clawdbot/daily-report.log
- 带时间戳的日志更易排查:2>&1 | ts '[%Y-%m-%d %H:%M:%S]' >> /var/log/clawdbot/daily-report.log(需安装 moreutils)
- 关键任务建议分离错误日志:2>> /var/log/clawdbot/daily-report.err >> /var/log/clawdbot/daily-report.out
- 临时调试可用:* * * * * env > /tmp/cron_env.txt 2>&1,对比终端 env 输出
时间字段逻辑避坑
日期(第3位)和星期(第5位)是“或”关系,不是“且”。但很多人误以为 0 2 15 * 6 是“每月15日且周六”,实际是“每月15日或每周六”。
- 要表达“每月15日且周六”,得用脚本内判断:0 2 15 * * [ $(date +\%u) = 6 ] && /path/to/script.sh
- 百分号 % 在 crontab 中是特殊字符,表示换行;要用 \% 转义,比如 date +\%Y-\%m-\%d
- 中文标点、全角空格、不可见字符都会导致解析失败,编辑务必用 vi/vim 或纯文本编辑器,禁用 VS Code 直接编辑 crontab -e











