ubuntu定时执行脚本---crontab详细使用指南

适用于 Ubuntu / Linux 系统


目录

  1. [什么是 crontab](#什么是 crontab)
  2. 基本使用
  3. 时间格式详解
  4. 特殊符号说明
  5. 常用时间表达式速查
  6. 实用示例
  7. 环境变量问题
  8. 日志与调试
  9. [系统级 crontab](#系统级 crontab)
  10. 常见问题

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                           │
│                                                                  │
│  注意:       命令用绝对路径、%需转义、输出重定向到日志              │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘
相关推荐
小昭在路上……2 小时前
编译与链接的本质:段(Section)的生成与定位
java·linux·开发语言
kida_yuan2 小时前
【以太来袭】5. Besu 组件组成与协同
运维·区块链
风曦Kisaki2 小时前
#Linux进阶Day04 用户 sudo 提权、IP 地址配置、SELinux 安全管理
linux·tcp/ip·安全
wzl202612133 小时前
基于规则引擎的新客欢迎语自动化:从0到1搭建智能破冰系统
大数据·运维·自动化
风酥糖3 小时前
在Termux中部署一个简单的服务导航页
linux·服务器·安卓
风曦Kisaki3 小时前
# Linux进阶Day03逻辑卷管理与RAID磁盘阵列
linux·运维·5g
与数据交流的路上3 小时前
linux-系统日志的归档
linux·运维·javascript
杭州杭州杭州3 小时前
Docker实验5
运维·docker·容器
释怀不想释怀3 小时前
硬盘分区:fdisk
linux·运维·服务器