crontab不执行主因是环境、权限、路径或时间逻辑问题:需用绝对路径或显式设PATH;确认用户权限与cron服务状态;脚本用绝对路径并重定向日志;特殊字符如%须转义,避免中文标点。
crontab 能跑起来,不等于能按你预期执行——绝大多数失败不是语法写错,而是环境、路径、权限或时间逻辑没对上。
crontab -e 编辑后不生效?先确认 cron 服务状态和用户权限
编辑保存后任务没触发,别急着改时间表达式。先看两件事:
-
systemctl status cron(Debian/Ubuntu)或systemctl status crond(CentOS/RHEL),确保服务是 active (running) - 普通用户执行
crontab -e前,检查/etc/cron.allow是否存在且包含该用户名;若不存在cron.allow,则需确认该用户未被列在/etc/cron.deny中 - root 用户默认总有权限,但非 root 用户有时会被系统策略限制(尤其在容器或加固环境中)
常见现象:crontab -e 保存成功,crontab -l 也能看到任务,但日志里完全没记录——大概率是服务没运行,或用户被 deny。
时间字段写对了,为什么还是“没执行”?重点查 PATH 和工作目录
crontab 默认只用极简 PATH=/usr/bin:/bin,不继承你的 shell profile。所以你在终端能直接敲 python3 或 mysqldump,cron 里很可能报 command not found。
Magician
Figma插件,AI生成图标、图片和UX文案
下载
- 在命令前加绝对路径:
/usr/bin/python3 /home/user/script.py,而不是python3 /home/user/script.py - 或在
crontab -e文件顶部显式声明:PATH=/usr/local/bin:/usr/bin:/bin - 脚本中涉及相对路径(如
./data/或../conf/config.yml)会失败——cron 启动时 cwd 是用户家目录,建议在命令前加cd /full/path/to/script/dir && - 想看真实执行环境?临时加一行:
* * * * * env > /tmp/cron_env.txt 2>&1,然后cat /tmp/cron_env.txt对比
*/5 * * * * 这类间隔写法,为什么实际执行间隔不准?
斜杠写法(如 */5)表示“从第 0 分钟开始,每 5 分钟一次”,即 0、5、10…55 分触发。但它不保证任务本身执行耗时不影响下一次调度。
- 如果某次任务执行超 5 分钟(比如备份卡住),下一次仍会在整点 +5 分准时启动——可能并发冲突
- 避免重叠:用
run-one类工具包装,或在脚本开头加锁(如if [ -f /tmp/myjob.lock ]; then exit; else touch /tmp/myjob.lock; ...; rm /tmp/myjob.lock; fi) - 注意:月份和星期字段同时指定时(如
0 2 15 * 6),表示“每月 15 日 *且* 周六”,不是“15 日或周六”——这是最常误读的逻辑
怎么验证 crontab 时间表达式是否符合本意?
别靠心算,也别只信“看起来像”。两个可靠办法:
- 用
systemctl status cron后翻日志:sudo journalctl -u cron -n 50 --since "2 hours ago",看有没有(user) CMD (xxx)记录及退出码 - 加输出重定向排查:
*/10 * * * * /path/to/script.sh &>> /var/log/myscript.log,注意用&>>同时捕获 stdout/stderr - 在线校验推荐:crontab.guru(输入表达式,它实时翻译成自然语言;但注意它不模拟环境,只校验时间逻辑)
真正容易被忽略的是:系统时区(timedatectl status)、夏令时切换、以及 /etc/crontab 和用户级 crontab 的格式差异(前者多一列用户名,后者没有)。
