配置crontab需规避日期+星期双触发坑(任一匹配即执行),命令用绝对路径并显式指定解释器,日志必须重定向且防爆盘,通过systemctl、crontab -l和syslog/messages验证执行。

配置 crontab 定时任务本身不难,关键在于让任务稳定、可追踪、不干扰系统——尤其是日志重定向处理不当,容易导致磁盘被撑爆或敏感信息泄露。
时间表达式别踩“日期+星期”双触发坑
很多人写 0 9 * * 1 想实现“每周一 9 点执行”,结果发现每月 1 号也跑了。这是因为 cron 的逻辑是:日期(day-of-month)和星期(day-of-week)**只要一个匹配就触发**,不是“同时满足”。
- 正确写法:只用星期字段控制周期,日期字段留
*—— 即0 9 * * 1 /path/to/script.sh - 如果真要限定“每月第一个周一”,得靠脚本二次判断,比如:
0 9 * * 1 [ $(date +\%d) -le 07 ] && /path/to/script.sh - 星期推荐用数字(0=周日,1=周一…6=周六),避免大小写或系统兼容性问题
命令必须用绝对路径,且显式指定解释器
crontab 执行环境极简,PATH 往往只有 /usr/bin:/bin,很多命令(如 php、python3、mysqldump)找不到。
- 写成:
0 2 * * * /usr/bin/python3 /home/user/backup.py,而不是0 2 * * * python3 backup.py - 脚本第一行加
#!/usr/bin/env python3不够,cron 不读 shebang,必须显式调用解释器 - 环境变量缺失?在命令前加完整 PATH 或在脚本开头 export:
0 2 * * * PATH=/usr/local/bin:/usr/bin:/bin /home/user/backup.sh
日志重定向必须明确,禁用默认邮件和无节制输出
默认情况下,cron 会把 stdout/stderr 发邮件给用户(常被忽略),而没重定向的脚本输出可能堆积在系统日志里,或静默丢失。
- 基础写法:
0 3 * * * /path/script.sh >> /var/log/myscript.log 2>&1
注意:2>&1必须写在>>后面,顺序不能错 - 防止日志无限增长:用
logrotate管理,或脚本内做轮转(如mv /var/log/myscript.log /var/log/myscript.log.$(date -d yesterday +\%Y\%m\%d)) - 敏感信息别进日志:脚本里避免打印密码、token、完整请求体;必要时用
grep -v过滤再记录 - 完全丢弃输出(仅需执行不关心结果):
>/dev/null 2>&1,但建议至少保留错误日志
验证与排错三步走
改完别急着等明天,立刻验证是否生效:
- 检查服务运行:
systemctl status cron(Debian/Ubuntu)或systemctl status crond(CentOS/RHEL) - 确认内容已加载:
crontab -l查看当前用户的全部任务;sudo cat /var/spool/cron/用户名直接读文件更可靠 - 查执行痕迹:
grep CRON /var/log/syslog(Ubuntu)或grep CRON /var/log/messages(CentOS),看有没有“completed”或“failed”


















