
crontab -l 看不到 /etc/cron.d/ 下的任务,因其仅显示当前用户级 crontab,而 cron.d 文件由 crond 进程独立加载,需检查日志、权限、命名及语法。
crontab -l 只显示当前用户的用户级 crontab(即 crontab -e 编辑的文件),完全不读取系统级目录 /etc/cron.d/ 中的任务。这是设计如此,不是 bug —— 系统级任务和用户级任务走的是两套加载机制。
系统级 cron.d 文件由 crond 进程在启动时或收到 SIGHUP 时扫描加载,路径固定为:/etc/cron.d/ 下所有非隐藏、可读、权限合规(不能被组/其他写)的文件。
.)或波浪线(~),否则会被忽略* * * * * root /path/to/script.sh
@reboot 或 @daily 等特殊时间语法,只接受标准五段时间格式直接查 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 之前)会因最后一行为空而跳过整个文件在脚本开头加一行日志输出,绕过 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 脚本/dev/null,导致你以为“没输出”,其实执行了即使 加载了文件,任务也可能因环境差异“看似没执行”。最典型的是 PATH 和 SHELL 不同:
/bin/sh,不是 /bin/bash;如果脚本里用了 [[ 或 source,可能直接报错退出PATH=/usr/bin:/bin,不含 /usr/local/bin 或用户 $HOME/bin;命令未带绝对路径就容易找不到$HOME、$USER),~ 在脚本中不会展开,cd ~ 会失败sudo killall -HUP crond 或重启服务真正难排查的,往往不是“没加载”,而是“加载了但执行失败又没留痕”。加绝对路径、显式指定 /bin/bash、重定向完整 stderr,比反复看 crontab -l 有用得多。