crontab任务不执行主因是环境变量缺失,需显式声明shell和path、用绝对路径、加日志重定向;%需转义或关闭邮件;systemd timer更适配服务依赖场景,需同名service+timer并启用timer单元。

crontab -e 保存后任务不执行?检查 SHELL 和 PATH
linux 的 cron 默认不读取用户 shell 环境(比如 ~/.bashrc),所以你在终端能跑通的命令,放进 crontab -e 就可能报错或静默失败。最常见的是找不到 python、node 或自定义脚本。
- 在 crontab 文件顶部显式声明:
SHELL=/bin/bash和PATH=/usr/local/bin:/usr/bin:/bin - 用绝对路径写命令,比如把
python3 script.py改成/usr/bin/python3 /home/user/script.py - 加日志重定向排查:
* * * * * /path/to/cmd >> /tmp/cron.log 2>&1 - 注意:系统级
/etc/crontab格式多一列用户名,而用户级crontab -e没有这一列
systemd timer 替代 cron?适合需要依赖和服务联动的场景
如果你的任务要等网络就绪、等某个服务启动、或执行失败后自动重试,cron 做不到,但 systemd timer 可以。它本质是把定时逻辑和 service 单元解耦,靠触发机制协同。
- 写一个
myjob.service描述要运行什么(Type=oneshot+ExecStart=...) - 再写一个同名的
myjob.timer,用OnCalendar=(如hourly)或OnBootSec=控制时机 - 启用时必须同时启动 timer:
systemctl enable --now myjob.timer,只开 service 不会定时触发 -
systemctl list-timers能看到下次触发时间,比crontab -l更直观
crontab 中 % 符号导致邮件发送失败?转义或重定向是刚需
cron 把 % 当作命令行换行符处理——它会把 % 之后的内容当成标准输入发给命令。如果你没配邮件系统,或者命令里真有 %(比如 date +'%Y-%m-%d'),就会出错或截断。
- 所有
%必须转义:date +'%Y-%m-%d' - 更稳妥的做法是彻底关闭邮件输出:
MAILTO=""放在 crontab 文件开头 - 或者统一重定向:
* * * * * /cmd 2>&1 >> /var/log/myjob.log,避免 cron 尝试发邮件 - 注意:有些发行版默认启用
sendmail,但未安装会导致 cron 日志刷屏(CRON) Error (No MTA installed)
service 和 timer 同名但状态不一致?systemctl status 看清楚单位类型
运行 systemctl status myjob 时,默认查的是 myjob.service。如果你只启了 myjob.timer,这里会显示 inactive (dead),容易误判为没生效。
- 查 timer 状态必须带后缀:
systemctl status myjob.timer - 查 service 执行结果看 journal:
journalctl -u myjob.service -n 20 - timer 触发 service 后,service 状态是瞬态的;别指望
systemctl is-active myjob.service长期返回active - 修改 timer 文件后,必须
systemctl daemon-reload,否则systemctl restart myjob.timer不生效
真正麻烦的不是写对某一行配置,而是不同机制(cron / systemd)对环境、路径、错误反馈的处理逻辑完全不同。改完记得验证日志输出,而不是只看“有没有报错”。