0%

定时任务

Linux 定时任务全指南:at 与 crontab 详解

在 Linux 系统中,定时任务是自动化运维的核心工具,能够帮助用户在指定时间自动执行脚本或命令。本文将详细介绍两种常用的定时任务工具:at(一次性任务)和 crontab(周期性任务),包括它们的使用方法、配置规则及实战技巧。

at:一次性定时任务

at 工具用于安排在未来某个特定时间执行一次的任务(如临时备份、定时发送邮件),依赖 atd 服务。

启动 atd 服务

at 命令需要 atd 守护进程支持,使用前需确保服务已启动:

1
2
3
4
5
6
7
8
# 启动 atd 服务
sudo service atd start

# 设置开机自启动(CentOS)
sudo chkconfig atd on

# 设置开机自启动(Ubuntu)
sudo systemctl enable atd

at 命令基本用法

1
at [选项] 时间
常用选项
  • -f 脚本文件:指定要执行的脚本(默认从标准输入读取命令)。
  • -m:任务执行完成后,通过邮件通知用户(需系统配置邮件服务)。
  • -c 作业号:查看指定作业的具体内容。
时间格式

at 支持多种时间表达方式,灵活易用:

  • 绝对时间:
    • HH:MM(如 14:30 表示下午 2:30)。
    • HH:MM YYYY-MM-DD(如 08:00 2024-10-01 表示 2024 年 10 月 1 日 8:00)。
    • HH:MM [am|pm] [月] [日](如 3pm 12 25 表示 12 月 25 日下午 3 点)。
  • 相对时间:
    • now + 数字 [minutes|hours|days|weeks](如 now + 30 minutes 表示 30 分钟后,now + 2 days 表示 2 天后)。
示例
1
2
3
4
5
6
7
8
9
10
# 10 分钟后执行 "echo '任务执行'" 命令
at now + 10 minutes
> echo '任务执行'
> <按 Ctrl+D 结束输入>

# 指定脚本在明天 9 点执行
at -f backup.sh 09:00 tomorrow

# 查看任务内容(假设作业号为 1)
at -c 1

管理 at 任务

  • 列出等待执行的任务

    1
    2
    3
    atq
    # 输出格式:作业号 执行时间 队列 用户
    # 示例:1 Fri Oct 1 09:00:00 2024 a root
  • 删除指定任务

    1
    2
    3
    atrm 作业号
    # 示例:删除作业号为 1 的任务
    atrm 1

crontab:周期性定时任务

crontab 用于创建周期性重复执行的任务(如每日备份、每小时日志清理),依赖 crond 服务,是生产环境中最常用的定时任务工具。

启动 crond 服务

1
2
3
4
5
6
7
8
# 启动 crond 服务
sudo service crond start

# 开机自启动(CentOS)
sudo chkconfig crond on

# 开机自启动(Ubuntu)
sudo systemctl enable cron

crontab 命令基本用法

1
crontab [选项]
常用选项
  • -e:编辑当前用户的定时任务(首次使用会提示选择编辑器)。
  • -l:列出当前用户的所有定时任务。
  • -r:删除当前用户的所有定时任务(谨慎使用)。
  • -u 用户名:管理指定用户的定时任务(需 root 权限)。
切换编辑器

默认编辑器可能为 nano,可通过以下命令切换为 vim

1
2
select-editor
# 选择对应编号的 vim 即可

时间表达式规则

crontab 的核心是时间表达式,格式为5 个字段,分别代表:

1
2
* * * * * 命令或脚本路径
# 分钟(0-59) 小时(0-23) 日(1-31) 月(1-12) 周(0-7,0和7均为周日)
特殊符号

通过特殊符号可灵活定义执行周期:

  • *:匹配任意值(如分钟位为 * 表示每分钟)。
  • ,:指定多个不连续的值(如 0 8,18 * * * 表示每天 8 点和 18 点)。
  • -:指定连续范围(如 0 9-17 * * 1-5 表示工作日 9 点到 17 点每小时执行)。
  • */n:每隔 n 单位执行(如 */10 * * * * 表示每 10 分钟执行)。
示例
时间表达式 含义
0 3 * * * 每天凌晨 3 点执行
0 12 * * 1 每周一中午 12 点执行
30 8 1 * * 每月 1 日早上 8:30 执行
*/15 * * * * 每 15 分钟执行一次
0 0 * * 5 每周五午夜 12 点执行(每周备份)
0 2 1,15 * * 每月 1 日和 15 日凌晨 2 点执行

配置文件与系统级任务

(1)用户级任务

用户通过 crontab -e 编辑的任务保存在 /var/spool/cron/crontabs/用户名 文件中,仅对该用户生效。

(2)系统级任务

系统级任务适用于所有用户,需编辑 /etc/crontab 配置文件(需 root 权限),格式与用户级任务略有不同,多了用户字段

1
2
# 分钟  小时  日  月  周  用户  命令
0 3 * * * root /usr/local/script/backup.sh
(3)预配置的周期目录

系统默认提供 4 个周期性任务目录,脚本放入对应目录后会自动按周期执行:

  • /etc/cron.hourly/:每小时执行一次。
  • /etc/cron.daily/:每天执行一次。
  • /etc/cron.weekly/:每周执行一次。
  • /etc/cron.monthly/:每月执行一次。

注意:放入这些目录的脚本需有可执行权限(chmod +x 脚本名),且不能带扩展名(如 backup 而非 backup.sh)。

管理与调试 crontab 任务

(1)查看任务
1
2
3
4
5
# 查看当前用户任务
crontab -l

# 查看其他用户任务(需 root 权限)
sudo crontab -l -u 用户名
(2)日志查看

crontab 执行日志默认保存在以下位置,可用于调试任务是否执行:

  • CentOS:/var/log/cron
  • Ubuntu:/var/log/syslog(需过滤 cron 关键字)
1
2
# 查看最近的 cron 日志
grep CRON /var/log/syslog
(3)常见问题排查
  • 任务未执行:
    • 检查脚本路径是否正确(建议使用绝对路径,如 /home/user/script.sh 而非 ./script.sh)。
    • 脚本是否有可执行权限(chmod +x 脚本)。
    • 环境变量问题:crontab 执行环境变量较少,建议在脚本中显式指定环境变量(如 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin)。
  • 邮件通知:若任务执行失败,系统可能发送邮件到 /var/spool/mail/用户名,可查看邮件内容定位错误。

at 与 crontab 的对比与选择

工具 适用场景 优势 局限性
at 一次性任务(如临时备份) 简单直观,时间表达灵活 仅执行一次,不适合周期性任务
crontab 周期性任务(如日志清理) 支持复杂周期,系统级 / 用户级任务分离 配置相对复杂,需学习时间表达式

选择建议

  • 临时的、一次性的任务 → 使用 at
  • 长期的、周期性的任务 → 使用 crontab

实战案例

案例 1:每日凌晨 2 点备份 MySQL 数据库(crontab)

  1. 创建备份脚本 backup_mysql.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/bash
    BACKUP_DIR="/data/backup/mysql"
    DATE=$(date +%Y%m%d)
    mkdir -p $BACKUP_DIR
    # 备份命令(需替换用户名和密码)
    mysqldump -u root -p123456 --all-databases > $BACKUP_DIR/mysql_$DATE.sql
    # 压缩备份文件
    gzip $BACKUP_DIR/mysql_$DATE.sql
    # 删除 7 天前的备份
    find $BACKUP_DIR -name "mysql_*.sql.gz" -mtime +7 -delete
  2. 赋予执行权限:

    1
    chmod +x backup_mysql.sh
  3. 添加到 crontab:

    1
    2
    3
    crontab -e
    # 添加以下内容(每天凌晨 2 点执行)
    0 2 * * * /home/user/backup_mysql.sh

案例 2:30 分钟后清理临时文件(at)

1
2
3
4
# 30 分钟后执行清理命令
at now + 30 minutes
> rm -rf /tmp/*
> <按 Ctrl+D 结束>

欢迎关注我的其它发布渠道