一、Cron 基础与命令

1.1 什么是 Cron

Cron 是 Linux/Unix 系统下的定时任务管理工具,允许用户按固定时间自动执行命令或脚本。

1.2 常用命令

命令说明风险等级
crontab -e编辑当前用户的 cron 任务(使用默认编辑器)
crontab -l查看当前用户的 cron 任务列表
crontab -r删除当前用户的所有 cron 任务⚠️ 高危(无确认)
crontab -i -r删除前确认(推荐替代 -r
crontab <filename>从文件导入 cron 任务
systemctl status crond检查 cron 服务是否运行(CentOS/RHEL)
systemctl restart crond重启 cron 服务(修改配置后可选)

1.3 用户级与系统级 Cron

类型配置文件位置说明
用户级crontab -e每个用户独立,推荐日常使用
系统级/etc/crontab需 root 权限,可指定执行用户
系统片段/etc/cron.d/*软件包安装的定时任务
小时任务/etc/cron.hourly/每小时执行(放入脚本)
日任务/etc/cron.daily/每天执行
周任务/etc/cron.weekly/每周执行
月任务/etc/cron.monthly/每月执行

二、Cron 时间格式详解

2.1 基础格式(5 个字段)

┌─────────── 分钟 (0-59)
│ ┌───────── 小时 (0-23)
│ │ ┌─────── 日期 (1-31)
│ │ │ ┌───── 月份 (1-12 或 JAN-DEC)
│ │ │ │ ┌─── 星期几 (0-7,0和7均为周日,或 SUN-SAT)
│ │ │ │ │
* * * * * 要执行的命令

2.2 特殊符号说明

符号说明示例
*所有值* * * * * 每分钟
,列举多个值0 8,12,18 * * * 每天8、12、18点
-范围0 9-17 * * * 9点到17点每小时
/步长*/5 * * * * 每5分钟
?不指定(仅日期/星期)部分实现支持
L最后一天/最后一个星期几0 23 L * * 每月最后一天23点
W最近工作日0 9 1W * * 最接近1号的工作日
#第几个星期几0 9 * * 1#3 每月第三个周一

2.3 常用时间示例

基础定时

# 每分钟执行一次
* * * * *

# 每5分钟执行一次
*/5 * * * *

# 每小时整点执行
0 * * * *

# 每天凌晨0点执行
0 0 * * *

# 每周日凌晨0点执行
0 0 * * 0

# 每月1日凌晨0点执行
0 0 1 * *

# 每年1月1日凌晨0点执行
0 0 1 1 *

组合与范围

# 每天9点到18点每小时执行
0 9-18 * * *

# 每天9:30和17:30执行
30 9,17 * * *

# 工作日(周一到周五)9点执行
0 9 * * 1-5

# 工作日的9点到17点每30分钟执行
0,30 9-17 * * 1-5

# 每小时的第0、15、30、45分钟执行
0,15,30,45 * * * *

高级示例

# 每月最后一天的23点执行
0 23 L * *

# 每月第三个星期一的9点执行
0 9 * * 1#3

# 每月1日的最近工作日的9点执行
0 9 1W * *

# 每12小时的第20分钟执行(8:20, 20:20)
20 */12 * * *

2.4 秒级精度(扩展格式)

标准 Cron 不支持秒,但部分系统(如 Java Quartz)支持 6 字段格式:

# 每10秒执行一次(Quartz格式)
*/10 * * * * *

# 每分钟的第30秒执行
30 * * * * *

三、Cron 日志与调试

3.1 查看 Cron 执行日志

# 实时监控 cron 日志
tail -f /var/log/cron          # CentOS/RHEL
tail -f /var/log/syslog | grep CRON  # Ubuntu/Debian

# 查看今天的 cron 记录
grep "$(date '+%b %d')" /var/log/cron

# 查看特定时间段
grep "Mar 25" /var/log/cron

3.2 任务输出重定向

Cron 任务的输出默认会发送邮件给用户,建议重定向到文件:

# 将输出写入日志文件(追加)
* * * * * /path/to/script.sh >> /var/log/script.log 2>&1

# 丢弃所有输出(不记录)
* * * * * /path/to/script.sh >/dev/null 2>&1

# 分别记录标准输出和错误
* * * * * /path/to/script.sh >> /var/log/script.log 2>> /var/log/script.err

3.3 测试 Cron 任务

# 方法1:临时设置为1分钟后运行
(crontab -l ; echo "$(date '+%M %H %d %m *' -d '1 minute') /path/to/script.sh") | crontab -

# 方法2:使用 at 命令立即测试
echo "/path/to/script.sh" | at now

# 方法3:手动执行验证
/path/to/script.sh

四、日志保留与轮转策略

4.1 默认保留策略

Cron 日志由 logrotate 管理,默认配置在 /etc/logrotate.d/syslog

/var/log/cron {
    rotate 4      # 保留 4 个旧日志
    weekly        # 每周轮转一次
    compress      # 压缩旧日志(.gz 格式)
    missingok
    sharedscripts
    postrotate
        /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
    endscript
}

实际保留情况

  • 当前日志 + 4 个归档 = 5 个文件
  • 保留天数:约 4~5 周(每周轮转一次)

4.2 查看现有日志文件

ls -lht /var/log/cron*

输出示例:

-rw-------. 1 root root  2.3M Mar 25 09:00 /var/log/cron
-rw-------. 1 root root  1.8M Mar 18 00:00 /var/log/cron-20240318.gz
-rw-------. 1 root root  2.1M Mar 11 00:00 /var/log/cron-20240311.gz
-rw-------. 1 root root  1.9M Mar 04 00:00 /var/log/cron-20240304.gz
-rw-------. 1 root root  2.0M Feb 26 00:00 /var/log/cron-20240226.gz

4.3 修改日志保留策略

方法1:修改全局默认配置(影响所有日志)

编辑 /etc/logrotate.conf

rotate 12     # 保留12个旧日志
weekly        # 每周轮转(或改为 monthly/daily)

方法2:仅修改 cron 日志配置

编辑 /etc/logrotate.d/syslog,为 /var/log/cron 单独添加规则:

/var/log/cron {
    missingok
    rotate 30     # 保留30个旧日志
    daily         # 每天轮转一次
    compress
    sharedscripts
    postrotate
        /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
    endscript
}

方法3:手动清理旧日志

# 删除 30 天前的 cron 日志
find /var/log -name "cron-*.gz" -mtime +30 -delete

五、最佳实践

5.1 使用绝对路径

Cron 的环境变量与终端不同,建议所有命令和脚本使用完整路径:

# 不推荐(可能找不到命令)
* * * * * python3 /home/user/script.py

# 推荐
* * * * * /usr/bin/python3 /home/user/script.py

# 或加载环境变量
* * * * * . /etc/profile; /usr/bin/python3 /home/user/script.py

5.2 脚本添加执行权限

chmod +x /path/to/script.sh

5.3 避免任务重叠执行

如果任务执行时间可能超过间隔,建议加锁:

# 使用 flock 防止重叠
* * * * * /usr/bin/flock -n /tmp/script.lock /path/to/script.sh

# 或使用 mkdir 实现锁
* * * * * mkdir /tmp/script.lock 2>/dev/null && /path/to/script.sh; rmdir /tmp/script.lock

5.4 记录关键任务日志

# 重要任务建议记录日志
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# 添加时间戳
0 3 * * * echo "$(date): Starting backup" >> /var/log/backup.log; /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

5.5 使用注释说明

# 每天凌晨3点备份数据库
0 3 * * * /usr/local/bin/backup.sh

# 工作日每30分钟检查服务状态
*/30 9-17 * * 1-5 /usr/local/bin/health_check.sh

六、常见问题与故障排查

Q1:Cron 任务未执行?

排查步骤

# 1. 检查 cron 服务是否运行
systemctl status crond   # CentOS/RHEL
systemctl status cron    # Ubuntu/Debian

# 2. 查看 cron 日志是否有错误
tail -50 /var/log/cron

# 3. 确认脚本有执行权限
ls -l /path/to/script.sh
chmod +x /path/to/script.sh

# 4. 检查命令路径是否正确
which python3  # 获取绝对路径

# 5. 查看邮件(如果有输出)
mail

Q2:Cron 执行但脚本部分失败?

原因:环境变量不同(PATH、JAVA_HOME 等)

解决方案

# 方法1:在脚本中加载环境变量
#!/bin/bash
source /etc/profile
source ~/.bashrc

# 方法2:在 cron 中指定环境变量
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * /path/to/script.sh

# 方法3:在命令前加载
0 3 * * * . /etc/profile; /path/to/script.sh

Q3:如何备份和恢复 Cron 任务?

# 备份当前用户的所有 cron 任务
crontab -l > cron_backup.txt

# 恢复备份
crontab cron_backup.txt

# 备份其他用户的(需要 root)
crontab -u username -l > username_cron_backup.txt

Q4:如何临时禁用 Cron 任务?

# 方法1:注释掉任务(编辑 crontab -e)
# 0 3 * * * /path/to/script.sh

# 方法2:重命名脚本文件
mv /path/to/script.sh /path/to/script.sh.disabled

# 方法3:删除所有任务前先备份
crontab -l > /tmp/cron_backup.txt
crontab -r

Q5:Cron 时区问题?

# 查看系统时区
timedatectl

# 修改时区(需重启 cron 服务)
sudo timedatectl set-timezone Asia/Shanghai
sudo systemctl restart crond

# 或在脚本中指定时区
0 3 * * * TZ=Asia/Shanghai /path/to/script.sh

七、快速参考速查表

7.1 常用命令速查

操作命令
编辑任务crontab -e
查看任务crontab -l
删除任务crontab -i -r
查看日志tail -f /var/log/cron
重启服务systemctl restart crond
修改保留策略vim /etc/logrotate.d/syslog
测试任务echo "命令" | at now

7.2 时间表达式速查

需求表达式
每分钟* * * * *
每5分钟*/5 * * * *
每小时0 * * * *
每天凌晨3点0 3 * * *
每周一9点0 9 * * 1
每月1号0点0 0 1 * *
工作日9点0 9 * * 1-5
9-17点每30分钟0,30 9-17 * * *

7.3 重定向速查

需求写法
记录所有输出>> /var/log/app.log 2>&1
丢弃所有输出>/dev/null 2>&1
分别记录>> app.log 2>> err.log

7.4 故障排查检查清单

  • cron 服务是否运行(systemctl status crond
  • 脚本是否有执行权限(chmod +x
  • 是否使用绝对路径(which command
  • 日志是否有错误(tail /var/log/cron
  • 环境变量是否正确(在脚本中加载 profile)