第47课:at 与 batch - 一次性任务调度
学习目标
- 掌握使用
at命令安排一次性定时任务的基本方法。 - 理解
at与batch命令的核心区别与应用场景。 - 学会查看、管理和删除
at队列中的待执行任务。 - 能够在实际运维场景中合理选择
at、batch或cron。
核心概念
在上一课中,我们学习了 cron,它非常适合安排那些需要周期性重复执行的任务,比如每天备份、每周生成报告。然而,在运维工作中,我们常常还需要处理另一类任务:只执行一次,且就在某个特定的未来时间点执行。
想象一下:
- “请在今晚11点重启数据库服务。”
- “请在系统负载降低后,运行一次数据清理脚本。”
- “服务器将在10分钟后维护,请在那时发送通知邮件。”
对于这类“一次性”的调度需求,cron 就显得有些“大材小用”和不够灵活了。为此,Linux 提供了 at 和 batch 两个命令。
1. at - 定时执行一次性任务
at 命令就像一个“预约单”。你告诉它一个未来的时间点(如 now + 5 minutes, teatime tomorrow, 10:00 PM),并输入你要执行的命令或脚本。at 会将你的任务和指令保存到 /var/spool/at/ 目录下的一个文件中,并由 atd 守护进程在指定的时间将其执行。
基本语法:
at [选项] [时间]
# 输入命令,按 Ctrl+D 结束输入
2. batch - 空闲时执行一次性任务
batch 命令是 at 的一个特殊变体。它不需要你指定一个具体的时间点。当你使用 batch 安排任务时,任务会被放入队列,但系统会等到负载较低(通常平均负载低于0.8)时才自动执行它。这对于那些不急于立刻执行,但希望在系统不忙的时候运行的资源密集型任务非常有用。
基本语法:
batch
# 输入命令,按 Ctrl+D 结束输入
3. at vs batch vs cron 对比
| 特性 | at / batch | cron |
|---|---|---|
| 执行频率 | 一次性 | 周期性 |
| 触发条件 | at: 精确时间点<br>batch: 系统空闲时 | 基于时间规则(分、时、日、月、周) |
| 典型场景 | 单次维护、延迟重启、负载敏感任务 | 日常备份、定期巡检、日志轮转 |
| 任务队列 | 有独立的 at 队列,用 atq 查看 | 通过 crontab -l 查看个人任务 |
| 任务文件 | /var/spool/at/ | /var/spool/cron/ |
代码示例
示例1:使用 at 安排一次性任务
# 安排一个在当前时间1分钟后执行的任务,创建一个标记文件
at now + 1 minutes <<EOF
touch /tmp/at_test_$(date +%s).txt
echo "Task executed by at at $(date)" >> /tmp/at_log.txt
EOF
# 查看当前用户的 at 任务队列
atq
# 查看某个具体任务(假设 job 编号是 3)的内容
at -c 3
# 删除一个待执行的任务(假设 job 编号是 3)
atrm 3
解释:
at now + 1 minutes:指定执行时间为“从现在开始的1分钟后”。<<EOF ... EOF:这是一种“Here Document”用法,用于将多行命令传递给at。atq:列出所有待执行的at任务。输出格式为:[任务ID] [执行时间] [队列] [用户]。at -c [任务ID]:查看该任务的详细环境变量和执行命令。atrm [任务ID]:从队列中删除指定任务。
示例2:使用 batch 安排任务
# 安排一个任务,当系统空闲时执行,记录开始执行的时间
batch <<EOF
echo "Batch job started at $(date)" >> /tmp/batch_log.txt
# 模拟一个耗时的查找任务
find / -name "*.log" -mtime +30 2>/dev/null > /tmp/old_logs_list.txt
EOF
# 使用 atq 同样可以查看 batch 任务(它们也存放在 at 队列中,但标记为 `=`)
atq
# 输出可能类似于:1 Thu Oct 26 15:30:00 2023 = user
# 等号 `=` 表示这是一个 batch 任务,时间字段显示的是提交时间。
解释:
batch命令直接使用,无需指定时间。- 提交后,任务进入
at队列,但状态为=。 atd守护进程会持续监控系统负载,一旦满足条件(负载低于阈值),就会执行该任务。
示例3:管理 at 服务和查看执行结果
# 确保 atd 服务正在运行(CentOS/RHEL)
sudo systemctl start atd
sudo systemctl enable atd
# 等待 at 任务执行完成后,检查结果
cat /tmp/at_log.txt
cat /tmp/batch_log.txt
实践练习
练习1:基础定时任务
- 使用
at命令安排一个任务,在 2分钟后 创建一个名为/tmp/exercise1.txt的文件,并将当前时间写入文件。 - 使用
atq确认任务已加入队列。 - 等待任务执行,然后检查
/tmp/exercise1.txt文件是否存在且内容正确。
预期命令与输出:
# 安排任务
echo "date > /tmp/exercise1.txt" | at now + 2 minutes
# 查看队列
atq
# 等待后检查
cat /tmp/exercise1.txt
# 输出应为类似:Wed Oct 25 14:30:00 CST 2023
练习2:复杂脚本一次性执行
- 编写一个简短的Shell脚本
backup_temp.sh,内容为:tar -czf /tmp/temp_backup_$(date +%Y%m%d%H%M).tar.gz /tmp/*.txt。 - 使用
at安排此脚本在 今天晚上11:00 (23:00 today或11 pm) 执行。 - 写出完整的
at命令(提示:可以使用输入重定向<从文件读取命令)。
预期命令:
# 创建脚本
echo 'tar -czf /tmp/temp_backup_$(date +%Y%m%d%H%M).tar.gz /tmp/*.txt' > backup_temp.sh
chmod +x backup_temp.sh
# 安排执行
at 23:00 today < backup_temp.sh
练习3:使用 batch 优化资源
- 系统当前负载可能较高。编写一个命令,使用
batch安排一个查找整个/etc目录下所有.conf文件的任务,并将结果列表保存到/tmp/conf_files_list.txt。 - 思考:为什么这个任务适合使用
batch而不是at?
预期命令:
batch <<EOF
find /etc -type f -name "*.conf" > /tmp/conf_files_list.txt
EOF
思考答案:因为 find /etc 是一个磁盘I/O密集型操作,如果在系统繁忙时执行,可能会加剧系统负担,影响关键服务。使用 batch 让它在系统空闲时自动执行,可以最小化对正常业务的影响。
常见错误
-
忘记指定时间:
- 错误:直接输入
at后回车,导致命令无法执行。 - 修正:
at必须接一个时间参数,如at now、at 15:00、at 17:00 tomorrow。
- 错误:直接输入
-
权限不足:
- 错误:普通用户试图删除其他用户的
at任务,或atd服务未运行。 - 修正:使用
sudo提权管理他人的任务,或使用sudo systemctl status atd检查服务状态。
- 错误:普通用户试图删除其他用户的
-
输出未重定向:
- 错误:
at或batch任务执行时,其标准输出和错误输出默认会通过邮件发送给用户,但如果未配置邮件系统,输出可能“丢失”,导致无法确认任务是否成功。 - 修正:始终在任务命令中加入重定向,如
command > /path/to/logfile 2>&1,以便记录输出。
- 错误:
-
误解
batch的执行条件:- 错误:认为
batch安排的任务会“立即”执行,或者指定一个具体时间。 - 修正:
batch的执行时机由系统负载决定,是不确定的。它只保证在负载低时执行,但不保证具体时间。如果需要精确时间,请使用at。
- 错误:认为
小结
at是安排在特定未来时间点执行一次性任务的命令。batch是安排在系统空闲时执行一次性任务的命令,适合非紧急的资源密集型任务。- 两者都使用
atq查看队列,atrm删除任务,at -c查看任务详情。 atd守护进程是执行这些任务的核心服务,必须确保其运行。- 选择策略:
- 精确时间点 ->
at - 空闲时执行 ->
batch - 周期重复 ->
cron
- 精确时间点 ->
- 良好实践:为
at/batch任务安排日志输出重定向,以便事后审计和调试。
练习编辑器
rust
Loading...