# Linux 定时任务 - crontab 命令详解与实践

URL: https://caijiao.org/linux/system/crontab
Source: docs/linux/system/crontab.md
Description: 全面学习 Linux 定时任务管理，掌握 crontab 命令语法、配置方法和最佳实践，实现系统自动化运维。

## 1. 定时任务概述

定时任务是 Linux 系统中自动化执行命令或脚本的重要机制，通过设置特定的时间规则，可以让系统在无人值守的情况下自动完成各种维护、备份、监控等操作。Linux 系统中最常用的定时任务工具是 crontab，它基于 cron 守护进程运行。

### 1.1 定时任务的重要性

- **自动化运维**：减少手动操作，提高工作效率
- **定期维护**：定期清理日志、备份数据、更新系统
- **监控预警**：定时检查系统状态，及时发现并报告问题
- **数据处理**：定期执行数据备份、同步、分析等操作

### 1.2 常用的定时任务工具

- **crontab**：标准的定时任务工具，适合大多数场景
- **at**：一次性定时任务
- **anacron**：非连续运行系统的定时任务工具
- **systemd-timers**：systemd 环境下的定时任务机制

## 2. crontab 基础

### 2.1 cron 守护进程

cron 是一个在后台运行的守护进程，负责检查系统中的定时任务配置并按时执行。在大多数 Linux 发行版中，cron 服务默认已启动并设置为开机自启。

```bash
# 检查 cron 服务状态
systemctl status cron

# 启动 cron 服务
systemctl start cron

# 停止 cron 服务
systemctl stop cron

# 设置 cron 服务开机自启
systemctl enable cron
```

### 2.2 crontab 命令概述

crontab 命令用于管理用户的定时任务列表。每个用户可以拥有自己的 crontab 文件，其中记录了需要定时执行的命令及其时间规则。

```bash
# 查看当前用户的 crontab 任务
crontab -l

# 编辑当前用户的 crontab 任务
crontab -e

# 删除当前用户的所有 crontab 任务
crontab -r

# 显示 crontab 的使用帮助
crontab -h
```

### 2.3 系统级与用户级 crontab

**系统级 crontab**：
- 位于 `/etc/crontab` 和 `/etc/cron.d/` 目录
- 需要指定执行用户
- 通常用于系统维护任务

**用户级 crontab**：
- 每个用户有自己的 crontab 文件，存储在 `/var/spool/cron/crontabs/` 目录
- 以用户身份执行
- 通过 `crontab` 命令管理

## 3. crontab 语法详解

### 3.1 时间格式

crontab 的时间格式由五个字段组成，分别表示分钟、小时、日、月、星期几，后面跟要执行的命令：

```
* * * * * command
- - - - -
| | | | |
| | | | ----- 星期几 (0-6, 0 表示周日)
| | | ------- 月份 (1-12)
| | --------- 日期 (1-31)
| ----------- 小时 (0-23)
------------- 分钟 (0-59)
```

### 3.2 特殊字符

| 特殊字符 | 描述 | 示例 |
|---------|------|------|
| `*` | 匹配所有值 | `* * * * *` 每分钟执行一次 |
| `,` | 列表分隔符 | `0 12 * * 1,3,5` 每周一、三、五中午12点执行 |
| `-` | 范围操作符 | `0 9-17 * * 1-5` 工作日9点到17点每小时执行一次 |
| `/` | 步进值 | `*/5 * * * *` 每5分钟执行一次 |
| `@reboot` | 系统启动时执行 | `@reboot command` |
| `@yearly` | 每年1月1日午夜执行 | `@yearly command` (等同于 `0 0 1 1 *`) |
| `@monthly` | 每月1日午夜执行 | `@monthly command` (等同于 `0 0 1 * *`) |
| `@weekly` | 每周日午夜执行 | `@weekly command` (等同于 `0 0 * * 0`) |
| `@daily` | 每天午夜执行 | `@daily command` (等同于 `0 0 * * *`) |
| `@hourly` | 每小时执行一次 | `@hourly command` (等同于 `0 * * * *`) |

### 3.3 命令格式

crontab 命令格式的完整语法：

```bash
# 注释行
* * * * * command >> /path/to/logfile 2>&1
```

其中：
- 注释行以 `#` 开头
- 命令可以是任何有效的 shell 命令或脚本路径
- 可以使用重定向将输出保存到日志文件

## 4. 创建和管理定时任务

### 4.1 创建第一个定时任务

1. 编辑 crontab 文件：

```bash
crontab -e
```

2. 添加定时任务（例如，每分钟显示当前日期和时间）：

```bash
* * * * * date >> /tmp/cron-test.log
```

3. 保存并退出编辑器

4. 查看已创建的任务：

```bash
crontab -l
```

5. 检查任务执行结果：

```bash
cat /tmp/cron-test.log
```

### 4.2 常用定时任务示例

#### 4.2.1 系统维护任务

```bash
# 每天凌晨2点清理系统临时文件
0 2 * * * find /tmp -type f -atime +7 -delete

# 每周日凌晨3点运行系统更新
0 3 * * 0 apt update && apt upgrade -y

# 每月1日凌晨4点清理旧日志文件
0 4 1 * * find /var/log -name "*.gz" -mtime +30 -delete
```

#### 4.2.2 备份任务

```bash
# 每天凌晨1点备份用户数据
0 1 * * * tar -czf /backup/home-$(date +\%Y\%m\%d).tar.gz /home

# 每小时备份数据库
0 * * * * mysqldump -u root -p'password' database > /backup/db-$(date +\%Y\%m\%d-\%H\%M).sql

# 每周一凌晨3点执行完整系统备份
0 3 * * 1 rsync -av / /backup/system/ > /var/log/system-backup.log 2>&1
```

#### 4.2.3 监控任务

```bash
# 每5分钟检查磁盘空间，低于10%时发送警报
*/5 * * * * df -h | grep '/dev/sda1' | awk '{ if($5+0 > 90) print "磁盘空间不足!" }' | mail -s "磁盘空间警报" admin@example.com

# 每小时检查网站可用性
0 * * * * curl -s -o /dev/null -w "%{http_code}" https://example.com | grep -v "200" && echo "网站可能宕机" | mail -s "网站可用性警报" admin@example.com

# 每天中午12点生成系统资源使用报告
0 12 * * * top -bn1 > /var/log/system-report-$(date +\%Y\%m\%d).log
```

### 4.3 管理多个定时任务

当有多个定时任务时，可以按照功能进行分组并添加注释，便于管理和维护：

```bash
# ========== 系统维护任务 ==========
# 每天凌晨2点清理临时文件
0 2 * * * find /tmp -type f -atime +7 -delete

# 每周日凌晨3点系统更新
0 3 * * 0 apt update && apt upgrade -y

# ========== 备份任务 ==========
# 每天凌晨1点备份用户数据
0 1 * * * tar -czf /backup/home-$(date +\%Y\%m\%d).tar.gz /home

# 每小时备份数据库
0 * * * * mysqldump -u root -p'password' database > /backup/db-$(date +\%Y\%m\%d-\%H\%M).sql

# ========== 监控任务 ==========
# 每5分钟检查磁盘空间
*/5 * * * * df -h | grep '/dev/sda1' | awk '{ if($5+0 > 90) print "磁盘空间不足!" }' | mail -s "磁盘空间警报" admin@example.com
```

## 5. 系统级定时任务

### 5.1 /etc/crontab 文件

系统级 crontab 文件 `/etc/crontab` 与用户级 crontab 格式略有不同，它需要指定执行命令的用户：

```bash
# 系统级 crontab 格式
* * * * * username command

# 示例
0 2 * * * root find /tmp -type f -atime +7 -delete
```

### 5.2 /etc/cron.* 目录

Linux 系统提供了几个特殊的 cron 目录，用于存放不同频率执行的脚本：

- `/etc/cron.hourly/`：每小时执行一次
- `/etc/cron.daily/`：每天执行一次
- `/etc/cron.weekly/`：每周执行一次
- `/etc/cron.monthly/`：每月执行一次

要添加系统级定时任务，只需将可执行脚本放入相应目录：

```bash
# 创建一个每小时执行的系统维护脚本
cat > /etc/cron.hourly/system-maintenance << 'EOF'
#!/bin/bash
# 清理内存缓存
echo 3 > /proc/sys/vm/drop_caches
# 更新系统负载统计
echo "系统负载: $(uptime)" >> /var/log/system-load.log
EOF

# 添加执行权限
chmod +x /etc/cron.hourly/system-maintenance
```

### 5.3 /etc/cron.d/ 目录

对于需要更精确时间控制的系统级任务，可以在 `/etc/cron.d/` 目录中创建配置文件：

```bash
# 创建一个自定义系统级定时任务
cat > /etc/cron.d/database-backup << 'EOF'
# 每小时备份数据库
0 * * * * mysql /usr/local/bin/db-backup.sh > /var/log/db-backup.log 2>&1
EOF
```

## 6. 定时任务的输出和日志

### 6.1 输出重定向

默认情况下，crontab 的执行结果会通过邮件发送给用户。为了避免邮件堆积，可以将输出重定向到文件：

```bash
# 将标准输出和错误输出都重定向到日志文件
* * * * * command >> /path/to/logfile.log 2>&1

# 将输出重定向到空设备（丢弃所有输出）
* * * * * command > /dev/null 2>&1
```

### 6.2 查看 cron 日志

系统会记录 cron 的执行情况，可以通过查看日志来监控定时任务：

```bash
# CentOS/RHEL 系统
tail -f /var/log/cron

# Ubuntu/Debian 系统
tail -f /var/log/syslog | grep CRON

# 通用方法（使用 journalctl）
journalctl -u cron -f
```

### 6.3 日志轮转

对于频繁执行的任务，日志文件可能会变得很大，建议配置日志轮转：

```bash
# 创建日志轮转配置
cat > /etc/logrotate.d/cron-scripts << 'EOF'
/path/to/logfile.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
}
EOF
```

## 7. 定时任务的调试和故障排除

### 7.1 常见问题和解决方案

| 问题 | 可能原因 | 解决方案 |
|------|---------|---------|
| 任务不执行 | 路径问题 | 使用绝对路径 |
| 任务不执行 | 权限问题 | 确保脚本有执行权限 |
| 任务执行错误 | 环境变量缺失 | 在脚本中设置必要的环境变量 |
| 任务执行错误 | 命令找不到 | 在 crontab 中使用完整的环境变量或绝对路径 |
| 邮件堆积 | 未重定向输出 | 将输出重定向到日志文件 |

### 7.2 调试技巧

```bash
# 方法1：在命令中添加详细日志
* * * * * { echo "开始执行任务: $(date)"; /path/to/command; echo "任务结束: $(date)"; } >> /path/to/debug.log 2>&1

# 方法2：临时增加执行频率
*/1 * * * * /path/to/command >> /path/to/debug.log 2>&1

# 方法3：手动测试 cron 环境
crontab -e
* * * * * env > /tmp/cron-env
# 然后比较 cron 环境和正常环境的区别
diff <(env) /tmp/cron-env
```

### 7.3 排错步骤

1. **检查命令语法**：手动在命令行执行脚本，确保无错误
2. **检查路径**：使用绝对路径
3. **检查权限**：确保脚本有执行权限
4. **检查环境变量**：在脚本开头设置必要的环境变量
5. **查看日志**：检查系统日志和脚本输出日志
6. **检查 cron 服务**：确保 cron 守护进程正在运行

## 8. 安全最佳实践

### 8.1 权限控制

```bash
# 限制 crontab 命令的使用权限
echo "username" > /etc/cron.allow
# 或
echo "username" > /etc/cron.deny

# 确保 crontab 文件权限正确
chmod 600 /var/spool/cron/crontabs/*
chmod 644 /etc/crontab
chmod 644 /etc/cron.d/*
```

### 8.2 脚本安全

- **最小权限原则**：以普通用户身份执行任务，仅在必要时使用 root
- **避免在 crontab 中存储敏感信息**：将密码等敏感信息存储在单独的配置文件中
- **验证脚本内容**：定期检查脚本是否被篡改
- **使用完整路径**：避免使用相对路径带来的安全风险

### 8.3 审计和监控

```bash
# 监控 crontab 文件的变更
cat > /etc/cron.daily/audit-crontabs << 'EOF'
#!/bin/bash
find /var/spool/cron/crontabs /etc/cron.d /etc/crontab -type f -mtime -1 -exec ls -la {} \; > /var/log/crontab-changes.log
EOF
chmod +x /etc/cron.daily/audit-crontabs
```

## 9. 高级定时任务技巧

### 9.1 嵌套脚本和依赖任务

对于复杂的任务，可以使用嵌套脚本结构：

```bash
# 主定时任务
0 1 * * * /usr/local/bin/main-task.sh

# main-task.sh 内容
#!/bin/bash
# 第一步：数据备份
/usr/local/bin/backup-data.sh

# 第二步：数据分析（仅在备份成功时执行）
if [ $? -eq 0 ]; then
  /usr/local/bin/analyze-data.sh
fi

# 第三步：清理旧数据
/usr/local/bin/cleanup-old-data.sh
```

### 9.2 防止任务重叠

使用锁文件避免任务重叠执行：

```bash
# 在脚本中添加锁文件机制
#!/bin/bash
LOCKFILE="/var/run/mytask.lock"

if [ -f "$LOCKFILE" ]; then
  echo "任务已经在运行中"
  exit 1
fi

trap "rm -f $LOCKFILE" EXIT
mkdir -p "$(dirname "$LOCKFILE")"

# 执行任务
# ...
```

### 9.3 随机延迟

对于多个服务器上的相同任务，可以添加随机延迟避免同时执行：

```bash
# 每天凌晨1-2点之间随机时间执行任务
0 1 * * * sleep $((RANDOM % 3600)) && /path/to/command
```

## 10. 替代方案和现代工具

### 10.1 systemd-timers

systemd-timers 是 systemd 环境下的定时任务机制，提供了更多功能：

```bash
# 创建定时器单元文件 /etc/systemd/system/backup.timer
cat > /etc/systemd/system/backup.timer << 'EOF'
[Unit]
Description=每日备份定时器

[Timer]
OnCalendar=*-*-* 01:00:00
Persistent=true

[Install]
WantedBy=timers.target
EOF

# 创建服务单元文件 /etc/systemd/system/backup.service
cat > /etc/systemd/system/backup.service << 'EOF'
[Unit]
Description=系统备份服务

[Service]
Type=oneshot
ExecStart=/usr/local/bin/system-backup.sh

[Install]
WantedBy=multi-user.target
EOF

# 启用并启动定时器
systemctl enable backup.timer
systemctl start backup.timer

# 查看活动的定时器
systemctl list-timers
```

### 10.2 anacron

anacron 适合非24小时运行的系统，确保错过的任务在系统开机后执行：

```bash
# 编辑 /etc/anacrontab
1 5 cron.daily run-parts /etc/cron.daily
7 10 cron.weekly run-parts /etc/cron.weekly
@monthly 15 cron.monthly run-parts /etc/cron.monthly
```

### 10.3 at 命令（一次性任务）

at 命令用于安排一次性执行的任务：

```bash
# 5分钟后执行命令
at now + 5 minutes
> echo "Hello World" > /tmp/at-test.txt
> Ctrl+D

# 今天下午3点执行命令
at 3pm today
> /path/to/script.sh
> Ctrl+D

# 查看待执行的 at 任务
atq

# 删除 at 任务
atrm <任务号>
```

## 11. 总结

crontab 是 Linux 系统中强大而灵活的定时任务工具，通过掌握其语法和最佳实践，可以实现系统运维的自动化，提高工作效率，减少人为错误。在实际应用中，应根据具体需求选择合适的定时任务方案，并注意安全和可靠性。

通过本文的学习，您应该能够：

- 理解 crontab 的基本原理和工作机制
- 熟练编写和管理各种定时任务
- 解决定时任务执行过程中的常见问题
- 遵循安全最佳实践，确保系统稳定运行
- 根据需求选择合适的定时任务工具

定时任务是 Linux 系统自动化运维的基础，合理使用这些工具可以大大简化系统管理工作，提高系统的可靠性和安全性。
