Linux 计划任务
在 Linux 系统中,计划任务分为两类:一次性延迟执行的
at任务和周期性重复执行的cron任务,熟练掌握这些工具是系统管理员的必备技能。
一、延迟用户作业 — at
1.1 at 简介
有时需要在将来某个设定的时间点运行一个命令或一组命令,这些计划好的命令通常被称为延迟任务。在 RHEL 中,at 命令提供了这一功能。
at 软件包提供了 atd 系统守护进程以及一组命令行工具。在默认情况下,atd 守护进程会自动安装并启用。
# 查看 atd 进程
ps -ef | grep atd
# 查看 atd 服务状态
systemctl status atd.service
atd 守护进程提供了 a 到 z 共 26 个队列,作业按字母顺序排列,队列越靠后,系统优先级越低。
1.2 相关命令与文件
| 命令/文件 | 说明 |
|---|---|
at | 计划新作业 |
atq | 查看待处理作业队列 |
atrm | 删除计划的作业 |
batch | 在系统负载允许时运行作业 |
/etc/at.allow | 白名单,允许使用 at 的用户 |
/etc/at.deny | 黑名单,禁止使用 at 的用户 |
/var/spool/at/ | 作业存储目录 |
1.3 TIMESPEC 时间格式
at 命令接受灵活的时间表达式,支持以下组合:
# 从现在起 5 分钟后
at now +5min
# 今天下午茶时间 (16:00)
at teatime
# 4 天后的中午
at noon +4 days
# 指定日期和时间
at 5pm august 3 2023
# 明天下午 4 点
at teatime tomorrow
# 2 小时后
at now +2 hours
1.4 at 命令使用示例
# 计划一个延迟任务
at 5pm august 3 2023
warning: commands will be executed using /bin/sh
at> wall hello
at> <EOT> # 按 Ctrl+D 结束输入
job 1 at Thu Aug 3 17:00:00 2023
# 从文件读取命令(适合复杂命令)
at now +1 hour < /path/to/script.sh
1.5 管理延迟作业
# 查看待处理作业
atq
# 输出示例:
# 1 Thu Aug 3 17:00:00 2023 a root
# 2 Sun Mar 12 12:00:00 2023 a root
# 输出各字段说明:
# 第一个字段:唯一作业编号
# 第二个字段:计划执行日期和时间
# 第三个字段:作业队列(默认 a)
# 第四个字段:作业所有者
# 查看作业的具体命令
at -c 1
# 删除作业
atrm 2
# 验证删除
atq
普通用户只能查看和控制自己的作业,root 用户可以查看和管理所有用户的作业。
1.6 用户权限控制
| 条件 | 结果 |
|---|---|
用户在 /etc/at.allow 中 | 允许使用 at |
用户在 /etc/at.deny 中 | 禁止使用 at |
| 用户同时在两个文件中 | 允许使用 at |
| 两个文件都不存在 | 只有 root 能使用 at |
| 文件存在但为空 | 所有用户均可使用 |
# 禁止 redhat 用户使用 at
echo redhat >> /etc/at.deny
# 允许 redhat 用户使用 at
echo redhat >> /etc/at.allow
二、周期性用户作业 — crond
2.1 crond 简介
按计划重复运行的作业被称为周期性作业。RHEL 系统默认自带了 crond 守护进程,由 cronie 软件包提供,默认启用并启动。
# 查看 crond 进程
ps -ef | grep crond
# 查看 crond 服务状态
systemctl status crond.service
如果计划命令生成了未被重定向的输出或错误,crond 守护进程会尝试通过电子邮件将该输出发送给作业所有者。
2.2 crontab 命令
| 命令 | 用途 |
|---|---|
crontab -l | 列出当前用户的计划作业 |
crontab -e | 编辑当前用户的作业 |
crontab -r | 删除当前用户的所有作业 |
crontab filename | 从文件导入作业(替换现有作业) |
crontab -u username -e | root 编辑指定用户的作业 |
# 普通用户管理自己的任务
crontab -e # 编辑
crontab -l # 查看
crontab -r # 删除所有
# root 管理其他用户的任务
crontab -u redhat -e
crontab -u redhat -l
2.3 crontab 时间格式
crontab 文件的字段按以下顺序显示:
分钟 小时 几号 月 星期几 命令
0-59 0-23 1-31 1-12 0-7
语法规则:
| 符号 | 说明 | 示例 |
|---|---|---|
* | 任意值,始终匹配 | * * * * * (每分钟) |
数字 | 精确值 | 0 5 * * * (每天5:00) |
x-y | 范围 | 9-17 (9点到17点) |
x,y | 列表 | 1,3,5 (第1,3,5) |
*/x | 间隔 | */5 (每5分钟/小时) |
对于月份和工作日,可以使用三个字母的英文缩写:
| 类型 | 缩写 |
|---|---|
| 月份 | Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec |
| 星期 | Sun, Mon, Tue, Wed, Thu, Fri, Sat (0=Sun, 7=Sun) |
2.4 crontab 示例
# 每年 2 月 2 日上午 9 点执行一次年度备份
0 9 2 2 * /usr/local/bin/yearly_backup
# 七月每周五上午 9 点到下午 5 点之间,每 5 分钟发送 Chime 邮件
*/5 9-16 * Jul 5 echo "Chime"
# 每个工作日午夜前两分钟运行日报脚本
58 23 * * 1-5 /usr/local/bin/daily_report
# 每个工作日上午 9 点发送检查邮件
0 9 * * 1-5 mutt -s "Checking in" boss@example.com % Hi there boss, just checking in.
# 每两分钟记录一次当前时间
*/2 * * * * date >> /tmp/mylog.txt
# 凌晨 2 点执行系统清理(输出重定向)
0 2 * * * /usr/local/bin/cleanup.sh > /dev/null 2>&1
百分比符号
%会被当作换行字符,百分号之后的所有内容通过 stdin 传给命令。
2.5 用户权限控制
与 at 类似,cron 也有权限控制文件:
| 文件 | 作用 |
|---|---|
/etc/cron.allow | 白名单,允许使用 crontab 的用户 |
/etc/cron.deny | 黑名单,禁止使用 crontab 的用户 |
规则:同时存在时允许优先;两个文件都不存在时只有 root 能使用。
# 拒绝 redhat 用户使用 crontab
echo redhat >> /etc/cron.deny
# 删除控制文件(仅 root 可用)
rm -rf /etc/cron.allow /etc/cron.deny
2.6 日志查看
# 查看 Cron 执行日志
tail -f /var/log/cron
三、周期性系统作业
3.1 系统 crontab 文件
系统管理员应使用系统范围的 crontab 文件,而不是使用 crontab 命令管理系统作业。系统 crontab 的作业格式与用户 crontab 类似,唯一区别是命令字段前面多了一个用户字段。
# /etc/crontab 示例格式
cat /etc/crontab
# SHELL=/bin/bash
# PATH=/sbin:/bin:/usr/sbin:/usr/bin
# MAILTO=root
#
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6)
# | | | | |
# * * * * * user-name command to be executed
3.2 周期性系统作业的位置
| 位置 | 用途 |
|---|---|
/etc/crontab | 默认系统 crontab(可能被包更新覆盖) |
/etc/cron.d/ | 自定义 crontab 文件(推荐使用) |
/etc/cron.hourly/ | 每小时执行的脚本 |
/etc/cron.daily/ | 每天执行的脚本 |
/etc/cron.weekly/ | 每周执行的脚本 |
/etc/cron.monthly/ | 每月执行的脚本 |
推荐在
/etc/cron.d/下创建自定义 crontab 文件,防止第三方软件包更新时覆盖/etc/crontab。
# 创建系统级定时任务
cat > /etc/cron.d/custom-task << 'EOF'
# 每天凌晨 3 点以 root 身份运行备份
0 3 * * * root /usr/local/bin/backup.sh
EOF
3.3 目录脚本要求
/etc/cron.hourly/、/etc/cron.daily/ 等目录中的脚本必须是可执行文件:
# 创建每日任务脚本
cat > /etc/cron.daily/user-count.sh << 'EOF'
#!/bin/bash
USERCOUNT=$(w -h | wc -l)
logger "There are currently ${USERCOUNT} active users"
EOF
chmod +x /etc/cron.daily/user-count.sh
四、anacron — 补救执行
4.1 anacron 简介
anacron 确保重要作业始终运行,不会因为系统在应执行作业时关闭或休眠而意外跳过。例如,如果由于系统重启而导致每日作业未按时运行,系统就绪后会自动执行。
/var/spool/anacron/ 中会为每个作业保存时间戳文件,用于确定作业上次运行的时间。
4.2 /etc/anacrontab 语法
每行包含四个字段:
以天为单位的间隔 延迟(分钟) 作业标识符 命令
# /etc/anacrontab 示例
# 环境变量
START_HOURS_RANGE=3-22
# 每日作业 (间隔1天,延迟5分钟运行)
1 5 cron.daily run-parts /etc/cron.daily
# 每周作业 (间隔7天,延迟25分钟运行)
7 25 cron.weekly run-parts /etc/cron.weekly
# 每月作业 (间隔30天,延迟45分钟运行)
@monthly 45 cron.monthly run-parts /etc/cron.monthly
| 字段 | 说明 |
|---|---|
| 间隔天数 | 整数或宏 @daily(1)、@weekly(7)、@monthly(30) |
| 延迟(分钟) | crond 启动后等待的时间 |
| 作业号 | 日志中标识作业的唯一名称 |
| 命令 | 要执行的命令 |
START_HOURS_RANGE 指定了作业运行的时间范围,超出此范围时作业将不会启动。
五、at 与 cron 对比
| 特性 | at | cron |
|---|---|---|
| 执行方式 | 一次性延迟执行 | 周期性重复执行 |
| 守护进程 | atd | crond |
| 队列数 | a-z 共 26 个 | 无队列概念 |
| 作业存储 | /var/spool/at/ | /var/spool/cron/ |
| 配置命令 | at, atq, atrm | crontab -e/-l/-r |
| 权限控制 | /etc/at.allow, /etc/at.deny | /etc/cron.allow, /etc/cron.deny |
| 适用场景 | 临时性、一次性任务 | 定期维护、监控、备份 |
六、最佳实践
- 使用绝对路径:crontab 中的命令始终使用绝对路径,避免 PATH 导致的命令找不到
- 重定向输出:将命令输出重定向到日志文件,避免产生大量邮件
- SHELL 环境变量:在 crontab 开头设置
SHELL=/bin/bash确保使用正确的 shell - 系统任务用 /etc/cron.d/:避免直接编辑
/etc/crontab - 脚本加可执行权限:放入
cron.daily等目录的脚本必须可执行 - 验证语法:使用
crontab -l验证,通过日志/var/log/cron确认执行情况