Linux cron 基础:crontab 语法详解、环境变量与日志配置
说实话,很多运维新手第一次接触 cron 都觉得它挺简单——不就是一行「分时日月周」再加个命令吗?我一开始也这么想,直到有一次线上脚本没跑,排查了半天才发现是环境变量的问题。嗯,这章咱们就把 cron 的底裤扒干净。
crontab 语法:五颗星加上命令
标准 crontab 行格式长这样:
分 时 日 月 周 命令(路径)
0 2 * * * /usr/local/bin/check_disk.sh
五个字段用空格隔开。每个字段的取值范围:
| 字段 | 范围 | 特殊符号 |
|---|---|---|
| 分 (minute) | 0‑59 | *, /, -, , |
| 时 (hour) | 0‑23 | *, /, -, , |
| 日 (day of month) | 1‑31 | *, /, -, , |
| 月 (month) | 1‑12 | *, /, -, , |
| 周 (day of week) | 0‑7 (0和7都代表周日) | *, /, -, , |
几个常用组合,我个人习惯记成「口诀」:
0 2 * * *– 每天凌晨2点整*/5 * * * *– 每5分钟一次0 8-17 * * 1-5– 工作日早8点到晚5点,每小时整点0 0 1 * *– 每月1号零点
0 0 15 * 5 表示每月15号 或 每周五零点执行,并不是同时满足。
环境变量:cron 最大的坑
我踩过最深的坑就是这个。cron 任务执行时,不会加载你手动 source 的 .bashrc 或 .bash_profile。它只继承非常基础的 PATH(通常是 /usr/bin:/bin),连 /usr/local/bin 都没有。你想想看,脚本里用的命令 docker、python3、aws 如果在那个 PATH 里找不到,cron 直接报错,而你连日志都看不到——这才是最气人的。
建议在 crontab 文件顶部显式设置环境变量:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
0 3 * * * /opt/scripts/backup.sh
记住了:SHELL、PATH、MAILTO 这三个变量,写在 crontab 最前面。我用这个方式后,再没因为环境变量出过问题。
~ 波浪号。cron 默认 shell 是 /bin/sh,很多发行版下 sh 不展开波浪号。改成 $HOME 就好了。
日志配置:看不到的故障等于没发生
默认 cron 日志在 /var/log/cron(RHEL/CentOS)或 /var/log/syslog(Debian/Ubuntu),但这些日志记录了所有 cron 调度事件,并不会把脚本的输出单独归档。
我建议的做法:在脚本内部重定向输出,或者直接在 crontab 行里追加:
0 2 * * * /opt/scripts/healthcheck.sh >> /var/log/healthcheck.log 2>&1
这样每次执行的标准输出和错误输出都追加到同一个文件。怕日志文件太大?可以配合 logrotate 做轮转。你看,一条命令就把审计和排错都解决了。
>/dev/null 2>&1)除非你确定永远不会出错。我见过太多人为了省事直接丢弃输出,出问题了连根毛都查不到。
一张图理清 cron 执行全景
下面这张 SVG 图把你刚才学的三个部分串起来:从编辑 crontab 到环境变量加载,再到日志落地。
从图里你能看到:编辑完 crontab 后,crond 守护进程每分钟检查时间是否匹配。匹配后第一步就是加载你在 crontab 中定义的环境变量(SHELL、PATH、MAILTO),然后真正的脚本才开始执行。最后输出被重定向到日志文件。每一步你都清楚,排查时才不会抓瞎。
几个实用工具与调试技巧
crontab -l列出当前用户的定时任务。注意:如果没任务,它会报no crontab for xxx,别慌。crontab -r删除全部任务。我建议先crontab -l > /tmp/mycron.bak备份一下再删。- 测试环境变量: 写一个
env > /tmp/cron_env.log的测试任务,看看实际执行时的环境变量列表。我在新服务器上总先跑这条确认。 - 查看最近一次执行时间: 在日志文件里
grep "cron" /var/log/syslog | grep 你的脚本名,能看到启动时间和 PID。
crontab -r 而不备份。我见过同事手滑,把整个服务器的定时任务全清空,幸好有 Git 仓库回滚。嗯,从那以后我的服务器 crontab 都会版本控制。