五个字段
* * * * * 要执行的命令
│ │ │ │ │
│ │ │ │ └─ 星期几 (0-7,0 和 7 都是周日)
│ │ │ └──── 月份 (1-12)
│ │ └─────── 日期 (1-31)
│ └────────── 小时 (0-23)
└───────────── 分钟 (0-59)
- 0 3 * * *
- 每天凌晨 3 点整。备份、清理日志最常用这个时间。
- */5 * * * *
- 每 5 分钟一次。
*/n表示"每隔 n"。 - 0 */2 * * *
- 每 2 小时的整点。
- 0 8 * * 1
- 每周一早 8 点。
- 0 0 1 * *
- 每月 1 号零点。
- @reboot
- 开机时执行一次。不用写五个字段。
复杂的时间表达式不用硬背,crontab.guru 这个网站输入表达式会用大白话告诉你什么时候执行。实际工作中大家都这么干。
基本操作
$ crontab -e # 编辑当前用户的定时任务(会打开 vi)
$ crontab -l # 查看
$ crontab -r # ⚠️ 删除全部!别手滑
$ sudo crontab -l -u devops # 看别的用户的
crontab -r 直接清空所有任务,不问确认。手滑按成 r 的事故很常见。
习惯:编辑前先 crontab -l > ~/cron.bak 存一份。
两个经典坑
坑一:环境变量
- 你的终端里
PATH包含/usr/local/bin、/usr/bin等一大堆目录,还加载了~/.bashrc。- cron 执行时
- 环境极其精简——
PATH通常只有/usr/bin:/bin,不加载你的 .bashrc。 - 后果
- 你脚本里写
python3 xxx.py或docker ps,cron 找不到这些命令,任务静默失败。
# 解法一:命令写绝对路径(最推荐)
0 3 * * * /usr/bin/find /var/log -name "*.log" -mtime +7 -delete
# 解法二:在 crontab 顶部声明 PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * mycommand
# 解法三:脚本开头自己 source 环境
#!/bin/bash
source /etc/profile
怎么知道命令的绝对路径:which find → /usr/bin/find。Day 02 说的"脚本里一律用绝对路径",根源就在这。
坑二:不重定向输出,出错你看不见
# ❌ 错误:出错了不知道
0 3 * * * /opt/check.sh
# ✅ 正确:标准输出和错误都记进日志
0 3 * * * /opt/check.sh >> /var/log/check.log 2>&1
- >>
- 追加到文件末尾(
>是覆盖,日志要用>>)。 - 2>&1
- 把错误输出(2)也并到标准输出(1)里。不加这个,报错信息不会进日志。
- 顺序不能反
- 必须是
>> 文件 2>&1。写成2>&1 >> 文件的话错误还是跑到屏幕上了。 - 完全不想要输出
> /dev/null 2>&1——扔掉一切。但排障时你会后悔的,建议还是留日志。
定时任务不执行,怎么查
- 1 · cron 服务在跑吗
systemctl status crond——服务都没起,任务当然不执行。- 2 · 任务被触发了吗
sudo tail -50 /var/log/cron(Day 03 提过这个文件)。能看到触发记录,说明时间表达式没问题,是脚本本身的问题。- 3 · 脚本有执行权限吗
ls -l /opt/check.sh——需要 x 权限(Day 06 学的)。chmod +x。- 4 · 是不是环境变量问题
- 看你重定向的那个日志。报 command not found 就是 PATH 问题,把命令改成绝对路径。
# 用极简环境跑你的脚本,能提前暴露 PATH 问题
$ env -i /bin/bash --noprofile --norc /opt/check.sh
这条命令很有用——它清空环境变量来执行,如果这样能跑通,放进 cron 基本也没问题。
系统级的定时任务
$ ls /etc/cron.d/ # 系统级任务(要多写一个"用户名"字段)
$ ls /etc/cron.daily/ # 丢个脚本进去,每天自动执行
$ ls /etc/cron.hourly/ # 每小时
$ cat /etc/crontab # 系统主配置
用户自己的 crontab -e 是五个时间字段 + 命令。
/etc/cron.d/ 下的文件是五个时间字段 + 用户名 + 命令——漏了用户名会导致整行失效,这是个高频错误。
顺带认识 systemd timer
$ systemctl list-timers --all
NEXT LEFT UNIT ACTIVATES
Mon 2026-09-08 00:00:00 8h left logrotate.timer logrotate.service
Mon 2026-09-08 01:15:00 9h left dnf-makecache.timer dnf-makecache.service
systemd timer 比 cron 强的地方:日志进 journal(journalctl -u xxx 直接看)、支持依赖关系、错过的任务可以补跑。
但 crontab 更简单、更通用,日常运维还是 cron 用得多。今天知道有 timer 这回事就行。
今天的面试点
「第一步看 /var/log/cron 有没有触发记录——有记录说明时间写对了,是脚本的问题;没记录就检查 crond 服务和时间表达式。」
「如果触发了但没效果,八成是环境变量问题——cron 的 PATH 很精简,脚本里的命令要写绝对路径。」
「另外输出一定要重定向到日志(>> xxx.log 2>&1),不然出错都不知道。」
这三点答全,说明你真被这个坑坑过。
0 3 * * * /usr/bin/find /var/log -name "*.log" -mtime +7 -delete >> /var/log/clean.log 2>&1
三个细节都在里面:绝对路径、-mtime +7(Day 05 学的加号是"以前")、输出重定向。
今天的练习
systemctl status crond确认服务在跑- 建个测试任务:
crontab -e加一行* * * * * /usr/bin/date >> /tmp/cron-test.log 2>&1(每分钟一次) - 等两分钟,
cat /tmp/cron-test.log看有没有内容 sudo tail -20 /var/log/cron,看触发记录长什么样- 重点:故意制造环境变量坑——写个脚本内容是
ncdu --version(不写绝对路径),放进 cron,看日志里报 command not found,然后改成绝对路径修好 - 用
env -i /bin/bash --noprofile --norc 你的脚本模拟 cron 环境测一次 - 测完记得
crontab -e把测试任务删掉
Week 06 是Shell 脚本:变量、条件循环,然后写出一个真正能拿去面试讲的巡检脚本。
第 28 天的产物,就是你简历上那一条「写过自动化巡检脚本」的底气。