← 回目录
25 Week 05 · 磁盘与软件 · 收尾

定时任务 crontab

今天填 Day 02 埋的那个坑:「脚本手动跑好好的,一放进 crontab 就不执行」——这是新手必踩的经典问题。

五个字段

先看懂时间格式
分 时 日 月 周
*  *  *  *  *  要执行的命令
│  │  │  │  │
│  │  │  │  └─ 星期几 (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   # 看别的用户的
-r 和 -e 挨得太近

crontab -r 直接清空所有任务,不问确认。手滑按成 r 的事故很常见。

习惯:编辑前先 crontab -l > ~/cron.bak 存一份。

两个经典坑

今天的核心

坑一:环境变量

为什么手动能跑、定时跑不了
你的终端里
PATH 包含 /usr/local/bin/usr/bin 等一大堆目录,还加载了 ~/.bashrc
cron 执行时
环境极其精简——PATH 通常只有 /usr/bin:/bin不加载你的 .bashrc
后果
你脚本里写 python3 xxx.pydocker pscron 找不到这些命令,任务静默失败。
三种解法
# 解法一:命令写绝对路径(最推荐)
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/findDay 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 问题,把命令改成绝对路径。
一个模拟 cron 环境的技巧
# 用极简环境跑你的脚本,能提前暴露 PATH 问题
$ env -i /bin/bash --noprofile --norc /opt/check.sh

这条命令很有用——它清空环境变量来执行,如果这样能跑通,放进 cron 基本也没问题

系统级的定时任务

除了 crontab -e,还有这些
$ ls /etc/cron.d/          # 系统级任务(要多写一个"用户名"字段)
$ ls /etc/cron.daily/      # 丢个脚本进去,每天自动执行
$ ls /etc/cron.hourly/     # 每小时
$ cat /etc/crontab         # 系统主配置
/etc/cron.d/ 里的格式多一个字段

用户自己的 crontab -e五个时间字段 + 命令

/etc/cron.d/ 下的文件是五个时间字段 + 用户名 + 命令——漏了用户名会导致整行失效,这是个高频错误。

顺带认识 systemd timer

cron 的现代替代
看系统里已有的
$ 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),不然出错都不知道。」

这三点答全,说明你真被这个坑坑过。

「写一个每天凌晨 3 点清理 7 天前日志的任务」

0 3 * * * /usr/bin/find /var/log -name "*.log" -mtime +7 -delete >> /var/log/clean.log 2>&1

三个细节都在里面:绝对路径、-mtime +7(Day 05 学的加号是"以前")、输出重定向。

今天的练习

敲完再走 · 约 15 分钟
  • 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 天的产物,就是你简历上那一条「写过自动化巡检脚本」的底气。