作为一名运维工程师,你是否经常需要在深夜执行备份?是否希望系统能自动清理日志?是否需要定期执行数据同步?计划任务就是为了解决这些周期性、定时性需求而存在的。
本文将全面讲解 Linux 中的两种计划任务工具:
at(一次性调度)和cron(循环调度),帮你掌握定时任务的创建,管理技巧。
简介
计划任务的作用
计划任务(Scheduled Tasks) 主要用于执行周期性或定时性的任务。最典型的应用场景是定期备份数据。
常见使用场景:
- 每天凌晨 2 点自动备份数据库
- 每周清理一次日志文件
- 每月 1 号生成报表
- 在特定时间执行系统维护
计划任务的分类
Linux 提供两种计划任务调度方式:
| 类型 | 命令 | 用途 | 适用场景 |
|---|---|---|---|
| 一次性调度 | at | 在指定时间执行一次任务 | 临时需要定时执行的操作 |
| 循环调度 | cron | 按照周期重复执行任务 | 日常的、周期性的定时任务 |
一次性调度执行:at
语法格式
at <TIMESPEC>
其中 <TIMESPEC> 是时间表达式,支持多种灵活的写法。
时间表达式示例
| 时间表达式 | 含义 | 说明 |
|---|---|---|
now +5min | 5 分钟后 | 相对时间,最常用 |
now +1hour | 1 小时后 | 也可以用 +1h |
now +2days | 2 天后 | 也可以用 +2d |
teatime tomorrow | 明天下午 4 点(16:00) | teatime 是 Linux 中的特殊时间点 |
noon +4 days | 第四天中午 12 点 | 相对时间 + 特殊时间点 |
5pm august 3 2020 | 2020 年 8 月 3 日下午 5 点 | 绝对时间 |
4:00 2025-11-27 | 2025 年 11 月 27 日凌晨 4 点 | 简洁的绝对时间 |
实战:创建一次性任务
初识一次性任务计划
场景:1 分钟后自动创建一个用户。
步骤 1:设置定时任务
[root@localhost ~]# at now +1min
at> useradd eeee
at> <EOT> ← 按 Ctrl+D 提交任务
job 2 at Mon May 25 15:04:00 2026
操作流程:
- 输入
at命令 + 时间- 进入
at>提示符,输入要执行的命令- 按 Ctrl+D 提交任务
- 系统返回任务编号和执行时间
步骤 2:查询待执行的任务
[root@localhost ~]# atq
2 Mon May 25 15:04:00 2026 a root
| 字段 | 说明 |
|---|---|
2 | 任务编号 |
Mon May 25 15:04:00 | 计划执行时间 |
a | 任务队列(默认为 a 队列) |
root | 提交任务的用户 |
步骤 3:验证执行结果
[root@localhost ~]# id eeee
uid=6672(eeee) gid=6673(eeee) 组=6673(eeee)
能查到用户信息,说明定时任务已成功执行!
常见错误
错误 1:atd 服务未启动
[root@localhost ~]# at now +1min
Can't open /var/run/atd.pid to signal atd. No atd running?
解决方法:
[root@localhost ~]# systemctl start atd
[root@localhost ~]# systemctl enable atd
at 命令的进阶用法
查看特定任务的内容:
[root@localhost ~]# at -c 3
这会显示任务编号为 3 的具体执行内容。
删除待执行的任务:
[root@localhost ~]# atrm 3
| 命令 | 用途 |
|---|---|
at | 创建一次性任务 |
atq | 查询待执行任务列表 |
atrm [编号] | 删除指定编号的任务 |
循环调度执行:cron
简介
cron 是 Linux 中最常用的定时任务调度器。
cron和crontab是不可分割的:
- cron 是后台守护进程(
crond),负责执行定时任务- crontab 是用户操作命令,用于创建、查看、删除定时任务
工作流程:
用户编写任务(crontab -e)
↓
任务保存到 /var/spool/cron/[用户名]
↓
crond 进程每分钟检查一次
↓
匹配时间则执行任务
查看 crond 进程状态
# 查看服务状态
[root@localhost ~]# systemctl status crond.service
# 查看进程
[root@localhost ~]# ps aux | grep crond
root 7538 0.0 0.1 126384 1684 ? Ss 15:01 0:00 /usr/sbin/crond -n
root 8441 0.0 0.0 112824 988 pts/0 R+ 15:13 0:00 grep --color=auto crond
crond 程序正常运行是计划任务执行的根本保障! 如果 crond 没有运行,所有定时任务都不会执行。
管理 cron 任务
常用命令
| 命令 | 用途 | 英文说明 |
|---|---|---|
crontab -e | 编辑/创建任务 | Edit jobs for the current user |
crontab -l | 查看任务列表 | List the jobs for the current user |
crontab -r | 删除所有任务 | Remove all jobs for the current user |
管理其他用户的任务(仅 root 可用):
# 查看指定用户的定时任务
[root@localhost ~]# crontab -u username -l
# 编辑指定用户的定时任务
[root@localhost ~]# crontab -u username -e
任务存储位置
[root@localhost ~]# ls /var/spool/cron/
如果目录为空,说明当前用户没有创建定时任务。
每个用户的定时任务以用户名为文件名保存在此目录中。
Cron 时间表达式(核心!)
语法格式:
# .---------------- 分钟 (0 - 59)
# | .------------- 小时 (0 - 23)
# | | .---------- 日期 (1 - 31)
# | | | .------- 月份 (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- 星期 (0 - 6) (周日=0 或 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * 命令或脚本
记忆口诀:分 时 日 月 周 → 命令
六个部分用空格隔开。
特殊符号说明
| 符号 | 含义 | 示例 | 说明 |
|---|---|---|---|
* | 任意值 | * * * * * | 每分钟执行 |
, | 多个值 | 0 2 1,4,6 * * | 每月的 1、4、6 日的 2 点执行 |
- | 范围 | 0 2 5-9 * * | 每月 5 日到 9 日的 2 点执行 |
/ | 间隔 | */5 * * * * | 每 5 分钟执行一次 |
时间表达式示例
| 表达式 | 含义 | 说明 |
|---|---|---|
0 * * * * | 每小时的 0 分执行 | 整点执行 |
*/5 * * * * | 每 5 分钟执行一次 | 间隔执行 |
0 2 * * * | 每天 2:00 整执行 | 最常用 |
0 2 1 * * | 每月 1 号 2:00 整执行 | 月初执行 |
0 2 14 * * | 每月 14 号 2:00 整执行 | 月中执行 |
0 2 14 2 * | 2 月 14 日 2:00 整执行 | 特定日期 |
0 2 * * 5 | 每周五 2:00 整执行 | 每周执行 |
0 2 * * 0 或 0 2 * * 7 | 每周日 2:00 整执行 | 周日执行 |
* * * * * | 每分钟执行 | 调试用,生产环境慎用 |
日期和星期的组合规则(重点!)
日期(日)和星期(周)之间的关系比较特殊,需要特别注意:
规则 1:日和周都不写(都是 *)→ 每天执行
0 2 * * * /mysql_back.sh
# 每天 2:00 整执行
规则 2:只写日期,周为 * → 按日期执行
0 2 14 * * /mysql_back.sh
# 每月 14 号 2:00 整执行
规则 3:日期为 *,只写周 → 按周执行
0 2 * * 5 /mysql_back.sh
# 不写日期,仅周生效
# 每周五 2:00 整执行
规则 4:日期和周都写 → 满足任一条件就执行(”或”的关系)
0 2 14 2 5 /mysql_back.sh
# 以下两种情况都会执行:
# 1. 2 月 14 日 2:00 整
# 2. 2 月的每周五 2:00 整
重要:当日期和周同时写了具体值(不是
*),它们是 “或”(OR) 的关系。只要满足其中一个条件,任务就会执行。
更多示例
# 每天 2:00 整
00 02 * * * ls
# 每月 1 号 2:00 整
00 02 1 * * ls
# 每年 2 月 14 号 2:00 整
00 02 14 2 * ls
# 每周日 2:00 整
00 02 * * 7 ls
# 每年 6 月的周五 2:00 整(特殊!)
00 02 * 6 5 ls
# 因为是"或"关系,实际是:
# - 每年 6 月的任意一天 2:00
# - 每年任意月份的周五 2:00
# 两个条件满足一个就执行
# 每月 14 号或每周日 2:00 整(两个时间都执行)
00 02 14 * 7 ls
# 每年 2 月 14 号 或 2 月的每周日 2:00 整
00 02 14 2 7 ls
实战:创建循环定时任务
场景:每分钟自动创建文件
步骤 1:准备执行脚本
[root@localhost ~]# vim /root/1.sh
#!/bin/bash
/usr/bin/touch /root/$(date +%F-%H-%M-%S).txt
步骤 2:赋予执行权限
[root@localhost ~]# chmod +x /root/1.sh
步骤 3:编写任务计划
[root@localhost ~]# crontab -e
# 输入以下内容:
* * * * * /root/1.sh
步骤 4:验证任务
# 查看任务列表
[root@localhost ~]# crontab -l
* * * * * /root/1.sh
# 等待几分钟后查看结果
[root@localhost ~]# ls -l /root/
总用量 74432
-rwxr-xr-x. 1 root root 58 5月 25 15:36 1.sh
-rw-r--r--. 1 root root 0 5月 25 15:38 2026-05-25-15-38-01.txt
-rw-r--r--. 1 root root 0 5月 25 15:39 2026-05-25-15-39-01.txt
-rw-r--r--. 1 root root 0 5月 25 15:40 2026-05-25-15-40-01.txt
-rw-r--r--. 1 root root 0 5月 25 15:41 2026-05-25-15-41-01.txt
-rw-r--r--. 1 root root 0 5月 25 15:42 2026-05-25-15-42-01.txt
-rw-r--r--. 1 root root 0 5月 25 15:43 2026-05-25-15-43-01.txt
-rw-r--r--. 1 root root 0 5月 25 15:44 2026-05-25-15-44-02.txt
-rw-r--r--. 1 root root 0 5月 25 15:45 2026-05-25-15-45-01.txt
每分钟都会自动生成一个带时间戳的文件!
生产环境实战场景
场景一:每日数据库备份
# 创建备份脚本
[root@localhost ~]# vim /root/db_backup.sh
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
mysqldump -u root -p'password' --all-databases > /backup/db_${DATE}.sql
find /backup/ -name "db_*.sql" -mtime +7 -delete # 清理 7 天前的备份
# 添加定时任务(每天凌晨 2 点执行)
[root@localhost ~]# crontab -e
0 2 * * * /root/db_backup.sh >> /var/log/db_backup.log 2>&1
场景二:日志清理
# 每周日凌晨 3 点清理过期日志
0 3 * * 0 find /var/log/ -name "*.log" -mtime +30 -delete
场景三:系统监控
# 每 5 分钟检查磁盘使用率
*/5 * * * * df -h | awk '$5+0 > 80 {print "警告: " $0}' >> /var/log/disk_alert.log
场景四:定时同步时间
# 每小时同步系统时间
0 * * * * /usr/sbin/ntpdate time.windows.com >> /var/log/ntp.log 2>&1
系统级定时任务
除了用户的 crontab -e,Linux 还有系统级别的定时任务配置文件:
# 系统级 crontab 文件
/etc/crontab
# 查看内容
[root@localhost ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
与用户 crontab 的区别:系统级
/etc/crontab多了一个用户名字段,可以指定以哪个用户身份执行命令。
系统级定时任务目录:
| 目录 | 执行频率 |
|---|---|
/etc/cron.hourly/ | 每小时执行一次 |
/etc/cron.daily/ | 每天执行一次 |
/etc/cron.weekly/ | 每周执行一次 |
/etc/cron.monthly/ | 每月执行一次 |
将脚本放到对应目录中,系统就会自动按周期执行。
调试与排障
问题 1:crontab 任务没有执行
排查步骤:
# 1. 检查 crond 服务是否运行
[root@localhost ~]# systemctl status crond
# 2. 检查任务是否存在
[root@localhost ~]# crontab -l
# 3. 检查脚本是否有执行权限
[root@localhost ~]# ls -l /root/1.sh
# 4. 手动执行脚本,看是否有报错
[root@localhost ~]# /root/1.sh
# 5. 查看 cron 日志
[root@localhost ~]# tail -f /var/log/cron
问题 2:脚本手动执行成功,但 cron 执行失败
常见原因:
环境变量问题:cron 的 PATH 环境变量很精简,建议使用绝对路径
# ❌ 不好的写法
* * * * * python3 /root/script.py
# ✅ 正确的写法
* * * * * /usr/bin/python3 /root/script.py没有配置输出:将标准输出和错误输出都重定向到日志文件
* * * * * /root/1.sh >> /var/log/myjob.log 2>&1脚本没有可执行权限
chmod +x /root/1.sh
at vs cron 对比
| 对比维度 | at | cron |
|---|---|---|
| 执行方式 | 一次性执行 | 周期性重复执行 |
| 适用场景 | 临时性定时任务 | 日常的、周期性的任务 |
| 命令 | at / atq / atrm | crontab -e / -l / -r |
| 时间表达 | 自然语言(now +5min) | 五个星号表达式 |
| 服务 | atd | crond |
| 任务存储 | /var/spool/at/ | /var/spool/cron/ |
日常使用建议:90% 的场景都应该使用 cron,
at仅适用于临时的一次性需求。
常见问题
Q1:如何编辑其他用户的 crontab?
# root 用户可以管理所有用户的定时任务
[root@localhost ~]# crontab -u username -e # 编辑
[root@localhost ~]# crontab -u username -l # 查看
[root@localhost ~]# crontab -u username -r # 删除
Q2:crontab 中 % 符号怎么处理?
在 crontab 中,% 有特殊含义(表示换行),需要转义:
# ❌ 错误写法
0 2 * * * date +%Y%m%d > /root/date.txt
# ✅ 正确写法(转义 %)
0 2 * * * date +\%Y\%m\%d > /root/date.txt
# ✅ 或者写成脚本(推荐)
0 2 * * * /root/date_script.sh
Q3:如何禁止某些用户使用 crontab?
# 编辑黑名单
[root@localhost ~]# vim /etc/cron.deny
# 添加要禁止的用户名,每行一个
user1
user2
/etc/cron.allow是白名单,如果存在则只有白名单中的用户可以使用 crontab。
Q4:如何让 crontab 输出邮件通知?
默认情况下,cron 任务的输出会发送邮件给任务所有者。可以配置:
# 在 crontab 中设置邮件地址
MAILTO=admin@example.com
0 2 * * * /root/backup.sh
最佳实践
始终使用绝对路径
# cron 的环境变量与用户登录环境不同
* * * * * /usr/bin/python3 /opt/script.py记录日志
* * * * * /root/backup.sh >> /var/log/backup.log 2>&1避免每分钟执行
- 生产环境中
* * * * *会给系统带来不必要的负担 - 调试完成后调整到合理的执行频率
- 生产环境中
脚本先行测试
- 编写好脚本后,先手动执行验证
- 确认无误后再加入 crontab
定期审查定时任务
# 查看所有用户的定时任务
for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ==="
crontab -u $user -l 2>/dev/null
done注意时区设置
# 确认系统时区
[root@localhost ~]# timedatectl
总结
通过本章节的学习,你应该掌握了:
- 理解计划任务的作用和分类
- 使用
at创建一次性定时任务 - 使用
atq查看待执行任务,使用atrm删除任务 - 理解 cron 和 crontab 的关系
- 掌握 cron 的五段时间表达式(分、时、日、月、周)
- 熟练使用特殊符号(
*、,、-、/) - 理解日期和星期的”或”关系
- 创建和管理循环定时任务(
crontab -e/-l/-r) - 掌握生产环境中的常见定时任务场景
- 排查 cron 任务不执行的常见问题
学习建议:计划任务是运维的必备技能。建议在自己的虚拟机上多练习:创建一个每分钟执行的定时任务,观察执行结果;配置每日备份任务,理解时间表达式的各种组合。实际操作一遍,胜过阅读十遍文档!