Category 女是世界杯

用本工具把 cron 表达式拼出来、确认下次执行时间符合预期、贴到服务器 crontab 里——本以为大功告成,结果定时任务一次也没跑。

这种”表达式正确但任务不触发”是 cron 最让人崩溃的场景。本文不再讲表达式语法(已有 Cron 5 分钟入门 和 时区 / DST 陷阱),专攻”配置上去不跑”的 9 类原因和排查路径。

第一步:看日志确认 cron 有没有起任务

90% 的”不跑”问题,在日志里就有答案。

系统cron 系统日志路径Debian / Ubuntu/var/log/syslog(过滤 grep CRON)CentOS / RHEL / Rocky/var/log/cronmacOSlog show --predicate 'process == "cron"' --last 1h容器(Docker)通常无日志——cron 服务可能没启

# Debian

grep CRON /var/log/syslog | tail -20

# CentOS

tail -20 /var/log/cron

两种典型输出:

Oct 10 08:15:01 host CRON[12345]: (me) CMD (python /home/me/job.py)

→ cron 起了任务(CMD 行),如果脚本没生效问题在脚本本身(继续看下面)。

(没有任何 CRON 日志)

→ cron 根本没起任务,问题在 cron 服务 / 表达式 / 用户身份(继续看下面)。

第二步:cron 没起任务的 4 种原因

A. cron 服务没在跑

systemctl status cron # Debian/Ubuntu

systemctl status crond # CentOS

Active: active (running) 才行。否则:

systemctl start cron && systemctl enable cron

Docker 容器特别注意——基础镜像默认不启 cron 服务,需要:

CMD ["cron", "-f"] # 前台运行

# 或

CMD ["sh", "-c", "cron && tail -f /var/log/cron.log"]

B. 用户 crontab vs 系统 crontab 弄反

位置编辑方式用户身份用户 crontabcrontab -e当前用户系统 crontab /etc/crontab直接编辑文件多一个”用户”字段/etc/cron.d/myjob直接编辑文件多一个”用户”字段/etc/cron.daily/myjob放可执行脚本root

最常见错乱:把”用户 crontab”格式(5 字段 + 命令)写进了 /etc/cron.d/(应 5 字段 + 用户 + 命令):

# /etc/cron.d/myjob 正确格式:

15 8 * * * me /home/me/job.sh

↑↑

用户字段

漏了用户字段 → 整行不解析。

C. crontab 文件结尾没换行

POSIX 规定 crontab 必须以换行结尾。漏了最后一个 newline——最后一个任务被吞,cron 不解析。

修复:

echo "" >> /etc/cron.d/myjob # 加一行空行

或者用 crontab -e 编辑时编辑器(vim、nano)会自动加结尾换行。

D. 表达式的”日 OR 周”陷阱

cron 表达式有个反直觉规则:

* * * * *

分 时 日 月 周

**当日字段和周字段都不是 ***时,触发条件是”日匹配 OR 周匹配”,不是 AND。

15 8 1,15 * 1-5

→ 不是”工作日的 1 号和 15 号”,而是”每月 1/15 日 OR 每个工作日”——几乎天天跑。

修复:

想要的语义写法每月 1/15 日15 8 1,15 * *(周字段 *)每个工作日15 8 * * 1-5(日字段 *)工作日 + 月初月中(AND)表达式做不到,脚本里加 if [ $(date +%d) -eq 1 ] || [ $(date +%d) -eq 15 ]

第三步:cron 起了任务但跑不通的 5 种原因

E. PATH 太短,命令找不到

cron 默认 PATH:

/usr/bin:/bin

你登录 shell 的 PATH:

/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:...

差异巨大——所有装在 /usr/local/bin、/opt/xxx/bin、~/.nvm/...、~/.cargo/bin 下的命令在 cron 里都找不到。

修复(推荐顺序):

# 1. 命令用绝对路径(最稳)

* * * * * /usr/local/bin/python3 /home/me/job.py

# 2. crontab 顶部设 PATH

PATH=/usr/local/bin:/usr/bin:/bin:/home/me/bin

* * * * * python3 /home/me/job.py

# 3. 脚本里 source 完整环境

* * * * * bash -lc '/home/me/job.sh'

# -l 让 bash 走登录 shell 流程,加载 /etc/profile / ~/.bash_profile

F. 命令里有 % 没转义

cron 把 % 当 stdin 分隔符——第一个 % 之后的内容被当成命令的输入。

# 错误(被截断在第一个 %):

* * * * * echo "$(date +%Y-%m-%d)" >> /tmp/log

# 正确(每个 % 转义):

* * * * * echo "$(date +\%Y-\%m-\%d)" >> /tmp/log

全文搜替换:crontab 里所有 % 一律改 \%,除非你故意当 stdin。

G. 输出没重定向,磁盘 / 邮件队列爆

cron 默认把任务的 stdout + stderr 邮件发给该用户。绝大多数生产环境没装 mail:

输出累积到 /var/spool/mail/ 或 /var/mail/

单条任务输出 1MB × 一天 1440 次 × 几年 → 文件几 GB

磁盘满了之后 cron 也跑不动

修复:所有 crontab 任务必须显式重定向输出:

* * * * * /home/me/job.sh >> /var/log/myjob.log 2>&1

# 不关心输出(不推荐,丢失调试信息):

* * * * * /home/me/job.sh > /dev/null 2>&1

# 滚动日志:

* * * * * /home/me/job.sh 2>&1 | logger -t myjob

H. 脚本在 sh 下行为不同

cron 调用的 /bin/sh 在 Debian/Ubuntu 上默认是 dash 不是 bash——dash 不支持 [[ ]]、<<<、{1..10}、数组等 bash 扩展。

症状:shell 里跑得好的脚本,cron 跑挂在某行语法错。

修复:

#!/bin/bash ← 脚本第一行

# 或者 crontab 里强制 bash:

* * * * * /bin/bash /home/me/job.sh

I. 工作目录不是你以为的

cron 任务的 cwd 是该用户的 home 目录(不是脚本所在目录)。

症状:脚本里用相对路径读 ./config.yml 找不到。

修复:脚本里先 cd:

#!/bin/bash

cd "$(dirname "$0")" || exit 1 # 切到脚本所在目录

./mycommand

或者全用绝对路径。

一份”cron 不跑”快速排查 checklist

按这个顺序逐项过,5 分钟定位 90% 问题:

#检查项命令1cron 服务在跑?systemctl status cron2在预期时间附近 cron 日志有 CMD 记录?grep CRON /var/log/syslog | tail3crontab 文件结尾有换行?tail -c 1 /etc/cron.d/myjob | xxd(应见 0a)4用 crontab -l 看到的表达式与预期一致?crontab -l -u me5命令是否用绝对路径?肉眼检查6是否所有 % 都转义为 \%?grep % /etc/crontab7是否给命令加了 >> log 2>&1 重定向?肉眼检查8把命令复制出来用 sh -c "..." 手动跑能成?测试9脚本第一行 shebang 是 #!/bin/bash 不是 #!/bin/sh?检查脚本

替代方案:systemd timer 更现代

cron 是 1975 年的设计,systemd timer 是 2010 年代的现代实现。新系统强烈推荐用 systemd timer:

能力cronsystemd timer错过后补跑(机器关机时)❌✅ Persistent=true错峰随机延迟❌✅ RandomizedDelaySec=资源限制(CPU / IO / 内存)❌✅依赖其它服务❌✅ Requires=日志统一❌ 多处✅ journalctl -u myjob学习成本低中

写一个 .timer + .service 文件即可——本工具未提供 systemd timer 生成器,但 cron 表达式可以直接用 OnCalendar= 字段,语义大部分对得上。

默认不做的事

不模拟服务器行为——本工具只生成表达式 + 预测下次执行时间,跑不跑要看服务器

不识别 Quartz / Spring 7 字段格式——本工具默认 5 字段,需要 7 字段(带秒、年)请额外加字段

不验证表达式的”实际跑通” ——能在工具上算出 next run time 不代表服务器上跑得通,要按本文 checklist 排查

写完 cron 表达式 → 用本工具验证下次执行时间 → 贴到 crontab → 务必加 >> log 2>&1 重定向——第一次跑不通时直接看日志,比猜原因快 10 倍。

如果定时任务跑的是数据处理脚本,用 DuckDB SQL 工作台 当数据工作台;如果是文件归档脚本,用 ZIP 打包 / 在线解压 写好流程再丢 cron;如果定时跑测试或健康检查,改用 systemd timer 或 GitHub Actions 的 schedule 触发器比 cron 稳得多。

top
Copyright © 2088 足球世界杯预选赛_荷兰世界杯 - twllb.com All Rights Reserved.
友情链接