主题模式
Are you an LLM? You can read better optimized documentation at /fe/linux/cron-jobs.md for this page in Markdown format
Linux Cron 定时任务详解:自动化运维必备技能
在 Linux 服务器上,很多任务需要定期执行——备份数据、清理日志、监控服务、同步文件等。Cron 是 Linux 自带的定时任务调度系统,可以让这些任务自动运行,无需人工干预。
相比手动执行,Cron 的优势:
- 自动化:设置一次,永久执行
- 精确控制:支持分钟、小时、日期、月份、星期五级别的调度
- 低资源占用:后台守护进程运行,几乎不占用资源
- 灵活配置:支持用户级和系统级定时任务
📅 Cron 表达式语法
基本格式
┌───────────── 分钟 (0-59)
│ ┌────────────── 小时 (0-23)
│ │ ┌─────────────── 日 (1-31)
│ │ │ ┌──────────────── 月 (1-12)
│ │ │ │ ┌───────────────── 星期 (0-7) 0和7都是周日
│ │ │ │ │
│ │ │ │ │
* * * * * command特殊字符
| 字符 | 含义 | 示例 |
|---|---|---|
* | 匹配任何值 | * * * * * 每分钟执行 |
, | 列举多个值 | 0,15,30,45 * * * * 每15分钟 |
- | 指定范围 | 0-5 * * * * 每小时前5分钟 |
/ | 指定步长 | */5 * * * * 每5分钟执行 |
? | 不指定值(仅在日和星期) | 0 0 * * ? 每天凌晨执行 |
常用表达式示例
| 表达式 | 含义 |
|---|---|
* * * * * | 每分钟执行 |
0 * * * * | 每小时执行(整点) |
0 0 * * * | 每天凌晨 0 点执行 |
0 0 * * 0 | 每周日凌晨执行 |
0 0 1 * * | 每月 1 号凌晨执行 |
0 0 1 1 * | 每年元旦凌晨执行 |
*/5 * * * * | 每 5 分钟执行 |
0 */2 * * * | 每 2 小时执行 |
0 9-18 * * * | 工作时间(9-18点)每小时执行 |
0 9,18 * * 1-5 | 工作日早晚各执行一次 |
0 0 * * 1-5 | 工作日每天凌晨执行 |
🔧 配置定时任务
用户级定时任务
bash
# 编辑当前用户的定时任务
crontab -e
# 查看当前用户的定时任务
crontab -l
# 删除当前用户的所有定时任务
crontab -r
# 备份当前用户的定时任务
crontab -l > crontab.backup
# 恢复定时任务
crontab crontab.backup系统级定时任务
bash
# 系统级定时任务目录
/etc/cron.d/
/etc/cron.daily/
/etc/cron.hourly/
/etc/cron.monthly/
/etc/cron.weekly/bash
# 创建系统级定时任务
nano /etc/cron.d/backup
# 格式:分 时 日 月 周 用户 命令
0 3 * * * root /root/scripts/backup.sh配置示例
bash
# 每天凌晨 3 点执行备份脚本
0 3 * * * /root/scripts/backup.sh
# 每小时执行日志清理
0 * * * * /root/scripts/clean-logs.sh
# 每周一凌晨 2 点执行系统更新
0 2 * * 1 /root/scripts/update-system.sh
# 工作日(周一到周五)早上 9 点发送日报
0 9 * * 1-5 /root/scripts/send-report.sh
# 每 30 分钟检查服务状态
*/30 * * * * /root/scripts/check-service.sh
# 每月 1 号凌晨 4 点清理临时文件
0 4 1 * * find /tmp -type f -mtime +7 -delete
# 每天 7:30 提醒喝水(输出到日志)
30 7 * * * echo "Time to drink water!" >> /var/log/water-reminder.log📝 编写定时任务脚本
脚本编写规范
bash
#!/bin/bash
# 脚本名称:每日数据备份
# 执行时间:每天凌晨 3 点
# 作者:ygjc
set -euo pipefail
LOG_FILE="/var/log/daily-backup.log"
BACKUP_DIR="/root/backups"
DATE=$(date +%Y%m%d_%H%M%S)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始执行备份..." >> "$LOG_FILE"
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 备份数据库
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份数据库..." >> "$LOG_FILE"
docker exec nextcloud-db mysqldump -u nextcloud -pnextcloud nextcloud > "$BACKUP_DIR/db-backup-$DATE.sql"
# 备份文件
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份文件..." >> "$LOG_FILE"
tar -czf "$BACKUP_DIR/files-backup-$DATE.tar.gz" /root/data/docker_data/nextcloud/data
# 清理 7 天前的备份
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 清理旧备份..." >> "$LOG_FILE"
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
find "$BACKUP_DIR" -name "*.sql" -mtime +7 -delete
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份完成!" >> "$LOG_FILE"
echo "----------------------------------------" >> "$LOG_FILE"脚本权限设置
bash
# 确保脚本可执行
chmod +x /root/scripts/backup.sh
# 限制脚本权限(仅 root 可执行)
chmod 700 /root/scripts/backup.sh🐛 调试与排查
查看 Cron 日志
bash
# Ubuntu/Debian
tail -f /var/log/syslog | grep CRON
# CentOS/RHEL
tail -f /var/log/cron
# 查看所有 Cron 相关日志
grep -i cron /var/log/syslog测试定时任务
bash
# 使用 run-parts 测试定时任务
run-parts --test /etc/cron.daily/
# 手动执行脚本测试
/root/scripts/backup.sh
# 模拟 Cron 环境执行
env -i /bin/bash -c "/root/scripts/backup.sh"
# 查看脚本输出
/root/scripts/backup.sh > /tmp/backup-test.log 2>&1
cat /tmp/backup-test.log常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 任务未执行 | 脚本路径错误 | 使用绝对路径 |
| 任务未执行 | 脚本无执行权限 | chmod +x script.sh |
| 任务未执行 | PATH 环境变量问题 | 在脚本中设置 PATH 或使用绝对路径 |
| 任务执行失败 | 依赖未安装 | 在脚本开头检查依赖 |
| 任务执行失败 | 用户权限不足 | 使用正确用户执行 |
| 日志无输出 | 日志级别问题 | 检查 /etc/rsyslog.d/50-default.conf |
| 时区问题 | Cron 使用 UTC 时区 | 修改 /etc/timezone |
🔒 安全加固
限制可访问 Cron 的用户
bash
# 创建允许访问 Cron 的用户列表
nano /etc/cron.allow
root
www-data
# 创建禁止访问 Cron 的用户列表(与 allow 互斥)
nano /etc/cron.deny审计定时任务
bash
# 检查所有用户的定时任务
for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ==="
crontab -u $user -l 2>/dev/null || echo "No crontab"
done
# 检查系统级定时任务
ls -la /etc/cron.d/
ls -la /etc/cron.daily/
ls -la /etc/cron.hourly/防止定时任务被篡改
bash
# 设置文件权限,仅 root 可修改
chmod 600 /etc/crontab
chmod 700 /etc/cron.d/
chmod 700 /etc/cron.daily/
# 监控定时任务文件变化
md5sum /etc/crontab > /var/lib/cron/crontab.md5
# 定期检查
md5sum -c /var/lib/cron/crontab.md5安全注意事项
- 不要使用
root用户执行不必要的任务:使用最小权限原则 - 避免在定时任务中使用交互式命令:如
apt upgrade可能需要确认 - 日志记录:所有脚本都应该记录日志
- 错误处理:脚本中使用
set -euo pipefail确保出错时停止 - 路径安全:使用绝对路径,避免 PATH 被篡改
⚡ 高级技巧
使用 anacron
适合不持续运行的服务器(如笔记本电脑):
bash
# 安装 anacron
apt install anacron
# 配置 anacron
nano /etc/anacrontab
# 格式:周期(天) 延迟(分钟) 任务标识 命令
1 5 cron.daily run-parts --report /etc/cron.daily
7 10 cron.weekly run-parts --report /etc/cron.weekly
@monthly 15 cron.monthly run-parts --report /etc/cron.monthly使用 systemd timers
现代 Linux 发行版推荐使用 systemd timers:
bash
# 创建 timer 文件
nano /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.targetbash
# 创建 service 文件
nano /etc/systemd/system/backup.service
[Unit]
Description=Daily backup service
[Service]
Type=oneshot
ExecStart=/root/scripts/backup.sh
[Install]
WantedBy=multi-user.targetbash
# 启用 timer
systemctl daemon-reload
systemctl enable --now backup.timer
# 查看 timer 状态
systemctl list-timers定时任务管理工具
| 工具 | 特点 | 适用场景 |
|---|---|---|
| Cron | 系统自带 | 简单定时任务 |
| Anacron | 开机后补执行 | 不持续运行的服务器 |
| Systemd Timers | 现代方案 | 复杂定时任务 |
| Celery Beat | Python 生态 | Python 项目 |
| Airflow | 复杂工作流 | 数据管道 |
📊 实用脚本示例
示例 1:数据库备份
bash
#!/bin/bash
# /root/scripts/db-backup.sh
set -euo pipefail
DB_NAME="nextcloud"
DB_USER="nextcloud"
DB_PASS="your_password"
BACKUP_DIR="/root/backups/db"
DATE=$(date +%Y%m%d)
mkdir -p "$BACKUP_DIR"
mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$BACKUP_DIR/$DB_NAME-$DATE.sql"
find "$BACKUP_DIR" -name "*.sql" -mtime +30 -delete示例 2:日志清理
bash
#!/bin/bash
# /root/scripts/clean-logs.sh
set -euo pipefail
LOG_DIRS=(
"/var/log"
"/root/data/docker_data/nginx/logs"
"/root/data/docker_data/jellyfin/logs"
)
for dir in "${LOG_DIRS[@]}"; do
if [ -d "$dir" ]; then
find "$dir" -name "*.log" -type f -mtime +7 -delete
find "$dir" -name "*.log.*" -type f -mtime +7 -delete
fi
done示例 3:服务健康检查
bash
#!/bin/bash
# /root/scripts/check-service.sh
set -euo pipefail
SERVICES=("jellyfin" "nextcloud" "pihole")
for service in "${SERVICES[@]}"; do
if ! docker ps --filter "name=$service" --format "{{.Names}}" | grep -q "$service"; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $service 服务未运行,正在重启..." >> /var/log/service-check.log
docker start "$service"
fi
done📋 配置清单
| 项目 | 推荐配置 |
|---|---|
| 脚本目录 | /root/scripts/ |
| 日志目录 | /var/log/ |
| 备份目录 | /root/backups/ |
| 脚本权限 | 700(仅所有者可执行) |
| 日志保留 | 30 天 |
| 检查频率 | 每 5-10 分钟检查关键服务 |
🔗 相关文章
- Docker 日志管理与 ELK Stack — 日志收集与分析
- Linux 文件权限详解 — 权限管理基础
- Linux 进程管理 — 服务监控
- Uptime Kuma 服务监控 — 服务可用性监控
- Docker Compose 模板库 — 服务部署
