crontab定时任务使用指南

#linux #运维 #最佳实践

总结
  • crontab 是 Linux 定时任务工具,格式:分 时 日 月 周 命令
  • 添加任务前先检查是否已存在,避免重复注册
  • 常用场景:定期清理日志、数据库备份、磁盘监控告警、服务健康检查
  • 脚本输出建议重定向到日志文件,方便排查执行情况

1. crontab 基础

1.1 时间格式

*  *  *  *  *  command
│  │  │  │  │
│  │  │  │  └── 星期(0-7,0 和 7 都表示周日)
│  │  │  └───── 月份(1-12)
│  │  └──────── 日期(1-31)
│  └─────────── 小时(0-23)
└────────────── 分钟(0-59)

常用示例:

0 1 * * *        # 每天凌晨 1 点
0 */6 * * *      # 每 6 小时执行一次
0 1 * * 1        # 每周一凌晨 1 点
0 1 1 * *        # 每月 1 号凌晨 1 点
*/5 * * * *      # 每 5 分钟执行一次

1.2 常用命令

crontab -l          # 查看当前用户的定时任务
crontab -e          # 编辑定时任务
crontab -r          # 删除所有定时任务(慎用)
crontab -u user -l  # 查看指定用户的定时任务

2. 定期清理日志

路径可按实际情况调整,脚本会检查任务是否已存在,避免重复注册。

#!/bin/sh
# 定期清理各服务日志,保留 180 天内的日志

cron_temp=$(mktemp)
crontab -l > "$cron_temp" 2>/dev/null

add_job_if_absent() {
    local tag="$1"
    local job="$2"
    if ! grep -qF "$tag" "$cron_temp"; then
        echo "添加任务: $tag"
        echo "$job" >> "$cron_temp"
    else
        echo "已存在: $tag,跳过"
    fi
}

# 应用日志,每天凌晨 1:00
add_job_if_absent "/home/logs/" \
    "0 1 * * * find /home/logs/* -mtime +180 -name '*.log' -exec rm -rf {} \;"

# Nginx 日志,每天凌晨 1:10
add_job_if_absent "/home/nginx/logs/" \
    "10 1 * * * find /home/nginx/logs/ -mtime +180 -name '*.log' -exec rm -rf {} \;"

# XXL-Job 日志,每天凌晨 1:20
add_job_if_absent "/data/applogs/xxl-job/" \
    "20 1 * * * find /data/applogs/xxl-job/* -mtime +180 -name '*.log' -exec rm -rf {} \;"

# Nacos 日志,每天凌晨 1:30
add_job_if_absent "/home/nacos/logs/" \
    "30 1 * * * find /home/nacos/logs/ -mtime +180 -name '*.log' -exec rm -rf {} \;"

crontab "$cron_temp"
rm -f "$cron_temp"

echo "当前定时任务:"
crontab -l

3. 数据库定时备份

MySQL 每天凌晨 2 点备份,保留最近 7 天:

#!/bin/bash
# /opt/scripts/mysql_backup.sh

DB_USER="root"
DB_PASS="your_password"
DB_NAME="your_database"
BACKUP_DIR="/data/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"

mkdir -p "$BACKUP_DIR"

# 备份并压缩
mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" | gzip > "$BACKUP_FILE"

if [ $? -eq 0 ]; then
    echo "$(date): 备份成功 -> $BACKUP_FILE"
else
    echo "$(date): 备份失败!" >&2
fi

# 删除 7 天前的备份
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -exec rm -f {} \;

注册定时任务:

# 每天凌晨 2 点执行,输出追加到日志
0 2 * * * /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

4. 磁盘空间监控告警

磁盘使用率超过阈值时发送告警(需要配置好 mail 命令或替换为其他通知方式):

#!/bin/bash
# /opt/scripts/disk_monitor.sh

THRESHOLD=85   # 告警阈值(%)
ALERT_EMAIL="ops@example.com"

df -h | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{print $5 " " $6}' | while read usage mount; do
    usage_num=${usage%%%}  # 去掉百分号
    if [ "$usage_num" -ge "$THRESHOLD" ]; then
        msg="[告警] $(hostname) 磁盘 $mount 使用率已达 $usage,请及时处理!"
        echo "$msg" | mail -s "磁盘空间告警" "$ALERT_EMAIL"
        echo "$(date): $msg" >> /var/log/disk_monitor.log
    fi
done

注册定时任务:

# 每小时检查一次
0 * * * * /opt/scripts/disk_monitor.sh

5. 服务健康检查与自动重启

检查服务是否存活,挂了自动拉起:

#!/bin/bash
# /opt/scripts/service_watchdog.sh

SERVICE_NAME="your-app"
START_CMD="/opt/your-app/bin/start.sh"
LOG_FILE="/var/log/watchdog.log"

if ! systemctl is-active --quiet "$SERVICE_NAME"; then
    echo "$(date): $SERVICE_NAME 未运行,尝试重启..." >> "$LOG_FILE"
    systemctl start "$SERVICE_NAME"
    if systemctl is-active --quiet "$SERVICE_NAME"; then
        echo "$(date): $SERVICE_NAME 重启成功" >> "$LOG_FILE"
    else
        echo "$(date): $SERVICE_NAME 重启失败,请人工介入!" >> "$LOG_FILE"
    fi
fi

注册定时任务:

# 每 5 分钟检查一次
*/5 * * * * /opt/scripts/service_watchdog.sh

6. 定时清理临时文件

清理 /tmp 下超过 3 天未访问的文件:

# 每天凌晨 3 点清理
0 3 * * * find /tmp -atime +3 -type f -exec rm -f {} \; 2>/dev/null

7. 注意事项

脚本要有执行权限

chmod +x /opt/scripts/your_script.sh

输出重定向,方便排查

# 正常输出和错误输出都写入日志
0 1 * * * /opt/scripts/your_script.sh >> /var/log/cron_your_script.log 2>&1

crontab 里用绝对路径

crontab 执行时环境变量和交互式 shell 不同,PATH 可能不包含常用命令目录,脚本里的命令和文件路径都用绝对路径,或者在脚本开头显式设置:

#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

测试脚本再注册

先手动执行脚本确认没问题,再注册到 crontab,避免静默失败。