适用于 Ubuntu / Linux 系统
目录
- [什么是 crontab](#什么是 crontab)
- 基本使用
- 时间格式详解
- 特殊符号说明
- 常用时间表达式速查
- 实用示例
- 环境变量问题
- 日志与调试
- [系统级 crontab](#系统级 crontab)
- 常见问题
1. 什么是 crontab
crontab(cron table)是 Linux 系统的定时任务调度器,可以让系统在指定时间自动执行命令或脚本。
┌─────────────────────────────────────────────────┐
│ crontab │
│ │
│ 用户编写定时规则 ──→ cron 守护进程 ──→ 自动执行 │
│ │
│ 例:每天凌晨 2 点自动备份数据库 │
│ 每 30 分钟检查一次磁盘容量 │
│ 每周一早上 9 点发送报告邮件 │
└─────────────────────────────────────────────────┘
工作原理
┌──────────┐ 读取规则 ┌──────────────┐
│ crontab │ ─────────────→ │ cron 守护进程 │
│ 配置文件 │ │ (crond) │
└──────────┘ └──────┬───────┘
│
时间匹配?│ 每分钟检查一次
▼
┌──────────────┐
│ 执行指定命令 │
└──────────────┘
2. 基本使用
常用命令
| 命令 | 说明 |
|---|---|
crontab -l |
列出当前用户的定时任务 |
crontab -e |
编辑当前用户的定时任务(首次会让你选择编辑器) |
crontab -r |
删除当前用户的所有定时任务(慎用!) |
crontab -u user -l |
查看指定用户的定时任务(需要 root 权限) |
编辑器选择
首次执行 crontab -e 时,系统会提示选择默认编辑器:
Select an editor. To change later, run 'select-editor'.
1. /bin/nano ← 最简单,推荐新手
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]: 1
- nano :操作简单,
Ctrl+O保存,Ctrl+X退出 - vim :功能强大,
Esc→:wq→ 回车保存退出
3. 时间格式详解
crontab 使用 5 个时间字段 + 1 个命令字段 来定义定时任务。
┌───────────── 分钟 (0 - 59)
│ ┌─────────── 小时 (0 - 23)
│ │ ┌───────── 日期 (1 - 31)
│ │ │ ┌─────── 月份 (1 - 12)
│ │ │ │ ┌───── 星期几 (0 - 7, 0和7都是周日)
│ │ │ │ │
│ │ │ │ │ ┌─── 要执行的命令
│ │ │ │ │ │
* * * * * command
图示说明
分钟 小时 日期 月份 星期
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
│ │ │ │ │ │ │ │ │ │ ──→ 命令
└──┘ └──┘ └──┘ └──┘ └──┘
0-59 0-23 1-31 1-12 0-7
示例: 30 2 * * * /backup.sh
│ │ │ │ │
│ │ │ │ └── 每周几(* = 每天)
│ │ │ └───── 每月(* = 每月)
│ │ └──────── 每几号(* = 每天)
│ └─────────── 2 点
└─────────────── 30 分
→ 每天凌晨 2:30 执行 /backup.sh
各字段取值范围
| 字段 | 含义 | 取值范围 |
|---|---|---|
| 第 1 位 | 分钟 | 0 - 59 |
| 第 2 位 | 小时 | 0 - 23 |
| 第 3 位 | 日期 | 1 - 31 |
| 第 4 位 | 月份 | 1 - 12 |
| 第 5 位 | 星期 | 0 - 7(0 和 7 都是周日) |
4. 特殊符号说明
| 符号 | 含义 | 示例 | 说明 |
|---|---|---|---|
* |
每一个 | * * * * * |
每分钟都执行 |
, |
列举多个值 | 0,30 * * * * |
每小时的第 0 和 30 分钟 |
- |
范围 | 9-17 * * * * |
第 9 到 17 小时(即 9:00-17:59) |
/ |
每隔 N 个单位 | */5 * * * * |
每隔 5 分钟 |
图解各符号
* (星号) ──── 代表"每一个"
* * * * * → 每分钟
0 * * * * → 每小时(每小时的第0分钟)
/ (斜杠) ──── 代表"每隔 N"
*/5 * * * * → 每隔5分钟
0 */2 * * * → 每隔2小时(0:00, 2:00, 4:00 ...)
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
│ 0│ 5│10│15│20│25│30│35│40│45│50│55│ → */5 的触发点
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
- (短横线) ─── 代表"范围"
9-17 * * * * → 每天9:00到17:59,每分钟都检查
0 8-12 * * * → 每天8:00, 9:00, 10:00, 11:00, 12:00
┌──┬──┬──┬──┬──┬──┬──┬──┬──┐
│ 8│ 9│10│11│12│13│14│15│...│ → 0 8-12 的触发点
└──┴──┴──┴──┴──┴──┴──┴──┴──┘
↑
8-12点
, (逗号) ──── 代表"和"
0 9,17 * * * → 每天 9:00 和 17:00
0,15,30,45 * * * * → 每小时的 0,15,30,45 分
5. 常用时间表达式速查
| 表达式 | 含义 | 说明 |
|---|---|---|
* * * * * |
每分钟 | 最频繁 |
*/5 * * * * |
每 5 分钟 | |
*/10 * * * * |
每 10 分钟 | |
*/30 * * * * |
每 30 分钟 | |
0 * * * * |
每小时整点 | 每小时的第 0 分钟 |
0 */2 * * * |
每 2 小时 | 0:00, 2:00, 4:00 ... |
0 */6 * * * |
每 6 小时 | 0:00, 6:00, 12:00, 18:00 |
0 0 * * * |
每天午夜 | 每天 0:00 |
0 2 * * * |
每天凌晨 2 点 | |
0 9 * * * |
每天早上 9 点 | |
30 8 * * * |
每天早上 8:30 | |
0 0 * * 0 |
每周日午夜 | |
0 9 * * 1 |
每周一早上 9 点 | |
0 9 * * 1-5 |
工作日早上 9 点 | 周一到周五 |
0 0 1 * * |
每月 1 号午夜 | |
0 2 1,15 * * |
每月 1 号和 15 号凌晨 2 点 | |
0 0 1 1 * |
每年 1 月 1 日 | |
@reboot |
开机时执行一次 | 特殊写法 |
6. 实用示例
示例 1:每天凌晨 2 点备份数据库
bash
0 2 * * * /usr/bin/mysqldump -u root mydb > /backup/mydb_$(date +\%Y\%m\%d).sql
┌──── 分钟: 0 (整点)
│ ┌── 小时: 2 (凌晨2点)
│ │ ┌─ 日期: * (每天)
│ │ │ ┌ 月份: * (每月)
│ │ │ │ ┌ 星期: * (不限)
0 2 * * * 命令
注意 :cron 中
%需要转义为\%,否则会被当作换行符。
示例 2:每 30 分钟检查磁盘容量
bash
*/30 * * * * /usr/bin/python3 /home/user/check_disk.py
示例 3:工作日每小时执行(9:00 - 18:00)
bash
0 9-18 * * 1-5 /home/user/work_task.sh
周一 周二 周三 周四 周五 周六 周日
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
│✓ │ │✓ │ │✓ │ │✓ │ │✓ │ × 不执行
└──┘ └──┘ └──┘ └──┘ └──┘
9点 10点 11点 ... 18点
示例 4:每 15 分钟同步文件
bash
*/15 * * * * rsync -avz /data/ /backup/data/
示例 5:每天下午 5:30 发送提醒
bash
30 17 * * * echo "下班了" | wall
示例 6:每月 1 号清理日志
bash
0 0 1 * * find /var/log -name "*.log" -mtime +30 -delete
示例 7:每小时执行,但只在工作时间
bash
0 8,9,10,11,12,13,14,15,16,17 * * 1-5 /home/user/task.sh
等价写法:
bash
0 8-17 * * 1-5 /home/user/task.sh
7. 环境变量问题
常见坑 :cron 执行时的环境变量与登录 shell 不同,PATH 往往不完整。
解决方法
方法一:在命令中使用绝对路径
bash
# ❌ 错误(可能找不到 python3)
0 * * * * python3 /home/user/script.py
# ✅ 正确(使用绝对路径)
0 * * * * /usr/bin/python3 /home/user/script.py
方法二:在 crontab 顶部定义环境变量
bash
# 在 crontab 文件顶部定义 PATH
PATH=/usr/local/bin:/usr/bin:/bin:/home/user/anaconda3/bin
SHELL=/bin/bash
HOME=/home/user
# 下面的任务就可以用简写
0 * * * * python3 /home/user/script.py
查看命令的绝对路径
bash
which python3 # 输出: /home/user/anaconda3/bin/python3
which bash # 输出: /usr/bin/bash
8. 日志与调试
方法一:输出重定向到日志文件
bash
# 标准输出和错误都追加到日志文件
0 * * * * /home/user/task.sh >> /home/user/task.log 2>&1
重定向说明:
>> file ──→ 标准输出(stdout)追加到 file
2>&1 ──→ 标准错误(stderr)重定向到标准输出
> file ──→ 标准输出覆盖 file(会丢失历史日志)
/dev/null ──→ 丢弃输出(不保留日志)
常用组合:
┌──────────────────────────────────────────┐
│ >> /var/log/cron.log 2>&1 保留所有输出 │
│ > /dev/null 2>&1 丢弃所有输出 │
│ >> /dev/null 2>&1 同上 │
└──────────────────────────────────────────┘
方法二:查看系统 cron 日志
bash
# Ubuntu / Debian
sudo grep CRON /var/log/syslog
# CentOS / RHEL
sudo tail /var/log/cron
方法三:通过 systemd journal 查看
bash
# 查看 cron 服务日志
sudo journalctl -u cron
# 实时跟踪
sudo journalctl -u cron -f
调试技巧
如果定时任务没有执行,逐步排查:
┌─────────────────────────────────────┐
│ 1. cron 服务是否运行? │
│ sudo systemctl status cron │
├─────────────────────────────────────┤
│ 2. crontab 是否正确写入? │
│ crontab -l │
├─────────────────────────────────────┤
│ 3. 命令是否用绝对路径? │
│ which python3 → /usr/bin/python3 │
├─────────────────────────────────────┤
│ 4. 脚本是否有执行权限? │
│ chmod +x /home/user/task.sh │
├─────────────────────────────────────┤
│ 5. 手动运行脚本是否正常? │
│ /usr/bin/python3 /home/user/... │
├─────────────────────────────────────┤
│ 6. 查看系统日志找报错 │
│ sudo grep CRON /var/log/syslog │
└─────────────────────────────────────┘
9. 系统级 crontab
除了用户级 crontab -e,系统还提供了全局配置:
配置文件位置
| 路径 | 说明 |
|---|---|
/var/spool/cron/crontabs/ |
各用户的 crontab 文件(不要直接编辑) |
/etc/crontab |
系统级 crontab(可指定运行用户) |
/etc/cron.d/ |
放置独立的定时任务文件 |
/etc/cron.hourly/ |
每小时执行的脚本目录 |
/etc/cron.daily/ |
每天执行的脚本目录 |
/etc/cron.weekly/ |
每周执行的脚本目录 |
/etc/cron.monthly/ |
每月执行的脚本目录 |
/etc/crontab 与用户 crontab 的区别
用户 crontab(crontab -e):
┌──────────────────────────────────────┐
│ 分 时 日 月 周 命令 │
│ * * * * * /home/user/task.sh │ ← 没有"用户"字段
└──────────────────────────────────────┘
系统 crontab(/etc/crontab):
┌──────────────────────────────────────┐
│ 分 时 日 月 周 用户 命令 │
│ * * * * * root /usr/local/task.sh │ ← 多一个"用户"字段
└──────────────────────────────────────┘
在 /etc/cron.d/ 中添加任务
bash
sudo nano /etc/cron.d/my-task
写入内容(注意要指定用户):
# 每小时以 root 身份执行清理
0 * * * * root /usr/local/bin/cleanup.sh
cron.daily 等目录的使用
只需把脚本放进去即可,不需要写时间表达式:
bash
# 将脚本复制到每日任务目录
sudo cp /home/user/backup.sh /etc/cron.daily/
sudo chmod +x /etc/cron.daily/backup.sh
10. 常见问题
Q1:为什么我的定时任务没执行?
按照以下顺序排查:
bash
# 1. 检查 cron 服务状态
sudo systemctl status cron
# 如果没有运行,启动它:
sudo systemctl start cron
sudo systemctl enable cron # 设为开机自启
# 2. 检查 crontab 是否正确
crontab -l
# 3. 检查日志
sudo grep CRON /var/log/syslog
Q2:脚本手动可以执行,但 cron 里不行?
最常见原因 :cron 的 PATH 环境变量与你的 shell 不同。
bash
# 查看当前 shell 的 PATH
echo $PATH
# 查看 cron 的环境变量
# 在 crontab 中临时添加:
* * * * * env > /tmp/cron_env.txt
# 一分钟后查看差异
diff <(env | sort) <(sort /tmp/cron_env.txt)
解决方案 :在 crontab 中设置 PATH,或所有命令使用绝对路径。
Q3:如何禁止某用户使用 crontab?
bash
# 创建 /etc/cron.deny 文件,每行一个用户名
sudo nano /etc/cron.deny
# 写入要禁止的用户名
baduser
对应的允许文件为 /etc/cron.allow(如果存在此文件,只有其中列出的用户才能使用 crontab)。
Q4:crontab 中 % 需要转义
在 crontab 的命令部分,% 会被解释为换行符,需要转义:
bash
# ❌ 错误
0 2 * * * date +"%Y-%m-%d"
# ✅ 正确
0 2 * * * date +"\%Y-\%m-\%d"
Q5:如何避免任务重复执行?
如果上一次任务还没执行完,下一次时间到了,可能产生重复执行。使用 flock 文件锁:
bash
*/5 * * * * flock -n /tmp/my_task.lock /home/user/task.sh
-n 表示非阻塞:如果锁被占用,直接跳过本次执行。
快速参考卡片
┌──────────────────────── crontab 快速参考 ────────────────────────┐
│ │
│ 时间格式: 分 时 日 月 周 命令 │
│ 0 2 * * * /backup.sh │
│ │ │ │ │ │ │
│ │ │ │ │ └── 0-7 (0/7=周日) │
│ │ │ │ └────── 1-12 │
│ │ │ └────────── 1-31 │
│ │ └────────────── 0-23 │
│ └────────────────── 0-59 │
│ │
│ 特殊符号: * = 每个 */N = 每隔N - = 范围 , = 列举 │
│ │
│ 常用命令: crontab -l (查看) crontab -e (编辑) │
│ crontab -r (删除全部) │
│ │
│ 调试: sudo grep CRON /var/log/syslog │
│ sudo systemctl status cron │
│ │
│ 注意: 命令用绝对路径、%需转义、输出重定向到日志 │
│ │
└──────────────────────────────────────────────────────────────────┘