服务器里的备份脚本、证书续期和数据同步经常交给 Cron 执行,最让人困惑的情况是脚本手动运行完全正常,放进 crontab 后却没有任何结果,终端也看不到报错。
这类问题多数不是时间表达式本身,而是 Cron 服务、任务所属用户、运行环境或输出处理出现了差异。下面按风险较低的顺序排查,先确认任务有没有被调度,再判断脚本为什么没有完成。

先确认Cron服务是否正常
Debian、Ubuntu 常见服务名是 cron,Rocky Linux、AlmaLinux、CentOS 常见服务名是 crond。先查看对应服务状态:
sudo systemctl status cron
或:
sudo systemctl status crond
如果服务处于停止或失败状态,可以先查看日志,再决定是否启动。直接执行重启可能让任务暂时恢复,却会丢掉导致服务失败的线索。
sudo journalctl -u cron --since today
sudo journalctl -u crond --since today
服务显示 active (running) 只代表调度器在运行,不能证明某一条任务已经执行成功。
确认任务写在了哪个用户下面
每个 Linux 用户都有自己的 crontab。普通用户执行 crontab -e 写入的任务,不会自动出现在 root 的计划任务里;使用 sudo crontab -e 编辑的则是 root 任务。
分别查看时可以使用:
crontab -l
sudo crontab -l
任务会以所属用户的权限运行。脚本需要读取网站目录、数据库备份或系统配置时,手动执行使用的账号与 Cron 所属用户不同,就可能出现权限不足。不要为了省事把所有任务都改成 root,更稳妥的做法是确认脚本实际需要哪些权限,再把目录所有权和读取范围配置准确。
/etc/crontab 与 /etc/cron.d/ 还有一个容易忽略的差别:系统级任务在时间字段后需要增加用户名,而用户自己的 crontab 不需要。把两种格式混用,任务就不会按预期执行。
用最小任务验证调度器
在检查复杂脚本前,可以临时增加一条只写入时间的测试任务:
* * * * * /usr/bin/date >> /tmp/cron-test.log 2>&1
等待两分钟后查看:
tail -n 5 /tmp/cron-test.log
如果文件持续增加时间记录,说明 Cron 服务、当前用户的 crontab 和基本调度没有问题,故障范围可以缩小到原脚本或执行环境。如果测试文件也没有出现,就继续检查系统日志、crontab 语法和任务所属用户。
测试结束后应删除这条临时任务,避免每分钟继续写文件。
手动能运行,Cron为什么不行
Cron 的运行环境比 SSH 终端精简得多。它不会自动加载用户登录时使用的全部环境变量,PATH 也可能不同。脚本里只写 php、python、node 或自定义命令时,终端能够找到程序,Cron 却可能提示找不到命令。
先在终端确认程序的完整路径:
command -v php
command -v python3
command -v node
随后在任务中使用绝对路径,例如:
0 3 * * * /usr/bin/php /var/www/example.com/scripts/backup.php >> /var/log/site-backup.log 2>&1
脚本内引用的配置文件、输出目录和相对路径也应检查。Cron 的当前工作目录未必是脚本所在目录,像 ./backup、../config 这样的相对路径很容易指向错误位置。可以在脚本开头主动切换目录,或者统一使用绝对路径。
检查脚本权限与换行格式
Shell 脚本需要正确的解释器声明和执行权限:
head -n 1 /opt/scripts/backup.sh
ls -l /opt/scripts/backup.sh
常见首行是:
#!/usr/bin/env bash
如果计划任务直接执行脚本,还需要让对应用户拥有执行权限:
chmod u+x /opt/scripts/backup.sh
从 Windows 上传的脚本可能带有 CRLF 换行,日志中会出现 bad interpreter 或包含 ^M 的报错。可以先用 file 检查,再使用 dos2unix 转换。不要看到权限错误就直接执行 chmod 777,这会扩大脚本被修改或滥用的范围,也未必解决解释器和路径问题。
把错误输出写进日志
定时任务没有终端窗口,脚本输出如果没有邮件服务接收,也没有重定向到文件,排查时就像任务什么都没做。建议在调试阶段同时记录标准输出和错误输出:
15 2 * * * /opt/scripts/backup.sh >> /var/log/backup-cron.log 2>&1
然后查看最近内容:
tail -n 100 /var/log/backup-cron.log
日志文件所在目录必须允许任务用户写入。普通用户无法写 /var/log/ 时,可以先输出到自己的目录,例如 /home/user/logs/backup-cron.log。确认任务稳定后,再结合日志轮转控制文件大小。
不同系统记录 Cron 调度信息的位置也不同。Debian、Ubuntu 可以查询 journalctl -u cron 或 /var/log/syslog,RHEL 系系统常见 /var/log/cron 或 journalctl -u crond。先从系统日志确认任务是否被触发,再看脚本日志确认执行到了哪一步。
修改后怎样确认真正恢复
不要只手动运行一次脚本就结束排查。正确的验收方式是让 Cron 在一个临时的近时间点自动执行,并同时确认三项结果:系统日志出现调度记录、脚本日志没有错误、目标文件或业务数据确实更新。
涉及备份的任务还要验证备份文件能否读取,文件大小是否合理。只看到目录里多了一个文件,不代表备份内容一定可恢复。
任务恢复后,把临时的每分钟频率改回正式计划,并删除测试文件。最终要验证的是调度、执行和业务结果三层都成功,而不是 crontab 列表里存在那一行。
常见问题
Cron任务修改后需要重启服务吗?
使用 crontab -e 保存的用户任务通常会被自动重新加载,不需要重启 Cron。若服务本身异常或修改了服务配置,应结合系统日志判断。
为什么脚本在SSH里正常,Cron里提示command not found?
最常见原因是 Cron 的 PATH 更精简。把程序和脚本改成绝对路径,并检查任务依赖的环境变量。
Cron可以执行需要sudo的命令吗?
不建议在任务中依赖交互式密码。确实需要系统权限时,应把任务放在合适的系统级调度位置,并只授予必要权限。
服务器关机期间错过的Cron任务会补跑吗?
传统 Cron 不会自动补跑关机期间错过的任务。需要补跑能力时,可以评估 anacron 或带持久化设置的 systemd timer。


