crontab -l 看不到 /etc/cron.d/ 下的任务,因其仅显示当前用户级 crontab,而 cron.d 文件由 crond 进程独立加载,需检查日志、权限、命名及语法。

crontab -l 为什么看不到 cron.d 下的任务
crontab -l 只显示当前用户的用户级 crontab(即 crontab -e 编辑的文件),完全不读取系统级目录 /etc/cron.d/ 中的任务。这是设计如此,不是 bug —— 系统级任务和用户级任务走的是两套加载机制。
系统级 cron.d 文件由 crond 进程在启动时或收到 SIGHUP 时扫描加载,路径固定为:/etc/cron.d/ 下所有非隐藏、可读、权限合规(不能被组/其他写)的文件。
- 文件名不能含点号(
.)或波浪线(~),否则会被忽略 - 必须有明确的用户名字段(第6列),例如
* * * * * root /path/to/script.sh - 不支持
@reboot或@daily等特殊时间语法,只接受标准五段时间格式
如何确认 /etc/cron.d/ 下的任务是否被 crond 加载
直接查 crond 的日志最可靠。多数发行版默认将 cron 日志发到 /var/log/cron(RHEL/CentOS)或 /var/log/syslog(Debian/Ubuntu)。用 grep 搜索 cron.d 目录相关线索:
sudo grep "cron.d" /var/log/cron 2>/dev/null || sudo grep "CRON" /var/log/syslog | grep -i "cron.d"
如果看到类似 READ /etc/cron.d/myjob 或 LOAD /etc/cron.d/myjob 的记录,说明已加载;若无,则可能是权限、命名或语法问题。
- 检查文件权限:
ls -l /etc/cron.d/myjob—— 必须是root:root,且不能有 group/others 的写权限(即0644合理,0664会被拒绝) - 检查文件末尾是否有空行:某些老版本
crond(如 v8.1.5 之前)会因最后一行为空而跳过整个文件 - 确认时间字段后紧跟着用户名,中间不能有多余空格或制表符混用(建议全用空格)
任务在执行但没日志?快速验证是否真由 cron.d 触发
在脚本开头加一行日志输出,绕过 syslog,直写文件:
echo "$(date): started by $(ps -o comm= $PPID)" >> /tmp/myjob.debug 2>&1
这样能区分是 cron.d 调用、手动运行,还是其他进程(比如 systemd timer 或另一个 crontab)触发的。
- 如果
$PPID对应的comm是crond,基本锁定是 cron.d 或系统 crontab 执行的 - 如果看到
bash或sh,再往上查ps -o pid,ppid,comm= $PPID,可能父进程是某个 wrapper 脚本 - 注意:有些任务会重定向 stdout/stderr 到
/dev/null,导致你以为“没输出”,其实执行了
常见静默失败原因:语法合法但不生效
即使 crond 加载了文件,任务也可能因环境差异“看似没执行”。最典型的是 PATH 和 SHELL 不同:
- 系统级 cron.d 默认使用
/bin/sh,不是/bin/bash;如果脚本里用了[[或source,可能直接报错退出 - 默认
PATH=/usr/bin:/bin,不含/usr/local/bin或用户$HOME/bin;命令未带绝对路径就容易找不到 - 没有继承 shell 的环境变量(如
$HOME、$USER),~在脚本中不会展开,cd ~会失败 - 某些发行版(如 Ubuntu)的 cron.d 会额外校验文件 mtime 是否早于 crond 启动时间,修改后需
sudo killall -HUP crond或重启服务
真正难排查的,往往不是“没加载”,而是“加载了但执行失败又没留痕”。加绝对路径、显式指定 /bin/bash、重定向完整 stderr,比反复看 crontab -l 有用得多。










