crontab 定时任务
crontab 是 Linux 系统自带的定时任务调度工具,可以按照设定的时间规则自动执行脚本或命令,白话说就是"定闹钟让电脑自动干活"。
核心知识点
| 概念 | 说明 |
|---|
| cron | 后台守护进程,负责按时执行任务 |
| crontab | 用户的定时任务配置表 |
| cron 表达式 | 5 个时间字段:分 时 日 月 周 |
| /etc/crontab | 系统级定时任务配置文件 |
| /etc/cron.d/ | 系统级定时任务目录 |
| /var/spool/cron/ | 用户级定时任务存放目录 |
| anacron | 适合不24小时开机的机器,会补执行错过的任务 |
安装配置
# 大多数 Linux 发行版自带 cron,确认是否安装
which crontab # 查看 crontab 命令是否存在
# Ubuntu/Debian 安装
sudo apt install cron # 安装 cron 服务
# CentOS/RHEL 安装
sudo yum install cronie # 安装 cronie 包
# 确认 cron 服务在运行
sudo systemctl status cron # Ubuntu/Debian
sudo systemctl status crond # CentOS/RHEL
# 设置开机自启
sudo systemctl enable cron # 确保重启后 cron 依然运行
基本使用
cron 表达式格式
┌──────────── 分钟 (0-59)
│ ┌────────── 小时 (0-23)
│ │ ┌──────── 日期 (1-31)
│ │ │ ┌────── 月份 (1-12)
│ │ │ │ ┌──── 星期 (0-7,0和7都是周日)
│ │ │ │ │
* * * * * 要执行的命令
# 特殊符号说明:
# * 表示"每一个"(每分钟、每小时...)
# */5 表示"每隔5个"(每5分钟、每5小时...)
# 1,3,5 表示"第1、3、5个"
# 1-5 表示"第1到第5个"
常用示例
# 每分钟执行一次
* * * * * /home/user/script.sh # 每分钟运行脚本
# 每小时的第 30 分钟执行
30 * * * * /home/user/script.sh # 每小时的 30 分执行
# 每天凌晨 2 点执行
0 2 * * * /home/user/backup.sh # 每天凌晨 2:00 备份
# 每周一早上 8 点执行
0 8 * * 1 /home/user/report.sh # 每周一 8:00 生成报告
# 每月 1 号凌晨执行
0 0 1 * * /home/user/monthly.sh # 每月 1 号 0:00 执行
# 每 5 分钟执行一次
*/5 * * * * /home/user/check.sh # 每隔 5 分钟检查一次
# 工作日(周一到周五)每天 9 点到 18 点,每小时执行
0 9-18 * * 1-5 /home/user/work.sh # 工作时间每小时执行
# 每天 8 点和 20 点执行
0 8,20 * * * /home/user/twice.sh # 一天执行两次
管理定时任务
# 编辑当前用户的定时任务
crontab -e # 打开编辑器编辑定时任务列表
# 查看当前用户的定时任务
crontab -l # 列出所有定时任务
# 删除当前用户的所有定时任务(危险!)
crontab -r # 删除所有定时任务,慎用
# 编辑指定用户的定时任务(需要 root 权限)
sudo crontab -u username -e # 编辑某用户的定时任务
# 查看指定用户的定时任务
sudo crontab -u username -l # 查看某用户的定时任务
高级用法
输出重定向与日志
# 把输出写入日志文件(追加模式)
0 2 * * * /home/user/backup.sh >> /var/log/backup.log 2>&1
# >> 追加输出到日志文件
# 2>&1 把错误输出也写入同一个文件
# 只记录错误,丢弃正常输出
0 2 * * * /home/user/backup.sh > /dev/null 2>> /var/log/backup_error.log
# > /dev/null 丢弃正常输出
# 2>> 追加错误到日志
# 完全不要任何输出(静默执行)
0 2 * * * /home/user/backup.sh > /dev/null 2>&1
# 所有输出都丢弃
环境变量设置
# 在 crontab 文件开头设置环境变量
SHELL=/bin/bash # 使用 bash 而不是默认的 sh
PATH=/usr/local/bin:/usr/bin:/bin # 设置 PATH,cron 默认 PATH 很短
MAILTO=admin@example.com # 任务输出发送到这个邮箱
HOME=/home/user # 设置 HOME 目录
# conda 环境的定时任务(生信常用)
0 2 * * * source /home/user/miniconda3/etc/profile.d/conda.sh && conda activate bioinfo && python /home/user/pipeline.py
# 必须先 source conda 初始化脚本,再激活环境,再执行命令
使用锁文件防止重复执行
# 使用 flock 防止任务重叠执行
*/5 * * * * flock -n /tmp/myapp.lock /home/user/slow_task.sh
# flock -n 获取锁,如果获取不到(上次还在跑)就直接跳过
# 这样就不会出现两个实例同时运行的情况
# 使用超时机制(最多跑 1 小时)
0 * * * * timeout 3600 /home/user/task.sh
# timeout 3600 表示最多执行 3600 秒(1小时),超时自动杀掉
特殊时间关键字
# 这些关键字可以替代 5 个时间字段
@reboot /home/user/startup.sh # 每次开机执行
@hourly /home/user/hourly.sh # 每小时(等于 0 * * * *)
@daily /home/user/daily.sh # 每天(等于 0 0 * * *)
@weekly /home/user/weekly.sh # 每周(等于 0 0 * * 0)
@monthly /home/user/monthly.sh # 每月(等于 0 0 1 * *)
@yearly /home/user/yearly.sh # 每年(等于 0 0 1 1 *)
系统级定时任务目录
# 系统预置的定时目录,直接把脚本丢进去就行
/etc/cron.hourly/ # 每小时执行里面的脚本
/etc/cron.daily/ # 每天执行里面的脚本
/etc/cron.weekly/ # 每周执行里面的脚本
/etc/cron.monthly/ # 每月执行里面的脚本
# 把脚本放进去(注意:脚本必须有执行权限,且不能有扩展名)
sudo cp backup.sh /etc/cron.daily/backup # 复制脚本到每日目录
sudo chmod +x /etc/cron.daily/backup # 加执行权限
常见报错
| 问题 | 原因 | 解决 |
|---|
| 定时任务不执行 | 脚本没有执行权限 | chmod +x script.sh |
| 命令找不到 | cron 的 PATH 很短,找不到命令 | 在脚本中使用绝对路径,或在 crontab 开头设置 PATH |
| conda 环境不生效 | cron 不会加载 .bashrc | 先 source conda.sh,再 conda activate |
| 脚本执行了但结果不对 | 工作目录不是预期的 | 在脚本开头 cd /正确/目录 |
| 收到大量邮件 | 任务有输出但没重定向 | 加 > /dev/null 2>&1 或设置 MAILTO="" |
| 时间到了没执行 | cron 服务没启动 | systemctl start cron 并 enable |
| 权限不够 | 用户没权限执行某些操作 | 用 sudo crontab -e 编辑 root 的定时任务 |
速查表
# === crontab 管理 ===
crontab -e # 编辑定时任务
crontab -l # 查看定时任务
crontab -r # 删除所有定时任务(慎用)
sudo crontab -u 用户 -l # 查看指定用户的定时任务
# === cron 表达式速记 ===
* * * * * # 每分钟
*/5 * * * * # 每 5 分钟
0 * * * * # 每小时
0 2 * * * # 每天凌晨 2 点
0 2 * * 1 # 每周一凌晨 2 点
0 0 1 * * # 每月 1 号
0 0 1 1 * # 每年 1 月 1 日
# === 特殊关键字 ===
@reboot # 开机执行
@hourly # 每小时
@daily # 每天
@weekly # 每周
@monthly # 每月
# === 日志与调试 ===
grep CRON /var/log/syslog # 查看 cron 执行日志(Ubuntu)
grep cron /var/log/cron # 查看 cron 日志(CentOS)
systemctl status cron # 查看 cron 服务状态
# === 输出重定向模板 ===
命令 >> /var/log/xxx.log 2>&1 # 所有输出追加到日志
命令 > /dev/null 2>&1 # 丢弃所有输出