at 命令详解与参数实测(Ubuntu 22.04)
基于 Ubuntu 22.04(at 3.2.5)逐参数实测 at:atd 服务启动与状态、warning 与 job 回显解读、队列查询 at -l/atq 与队列标记、at -c 任务全文逐段解读、-f 文件提交与 -M 禁邮件、时间格式族(now + N、10:30 tomorrow、midnight/noon/teatime)、65 秒真实执行实证、无 MTA 时输出丢弃与日志、atrm 删除与 batch 低负载执行。
at 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 at 的每一个常用参数——atd 服务启动与状态、任务提交的 warning 与 job 回显解读、队列查询
at -l/atq与 a/= 队列标记、at -c任务全文逐段解读、-f从文件提交、-M禁止发邮件、时间格式族(now + N分钟/小时/天、10:30 tomorrow、midnight/noon/teatime)、65 秒等待的秒级真实执行实证、无 MTA 时的输出丢弃与日志、atrm删除与batch命令,全部命令与回显已在 Ubuntu 22.04(at 3.2.5)实测通过。
一、环境信息
本文所有命令与回显均在以下环境实测采集,读者在相同版本的 Ubuntu 上可直接复现:
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| 架构 | x86_64 |
| at 包版本 | 3.2.5-1ubuntu1(at 命令、atq、atrm、batch 同属此包) |
| 调度守护进程 | /usr/sbin/atd(service atd 管理) |
| 任务队列落盘目录 | /var/spool/cron/atjobs/ |
| 日志载体 | /var/log/syslog(由 rsyslog 落盘) |
| 演示目录 | /root/demo/at |
环境确认命令与实测回显如下:
$ head -2 /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
$ uname -m
x86_64
$ dpkg -l at | tail -1
ii at 3.2.5-1ubuntu1 amd64 Delayed job execution and batch processing
$ at -V
at version 3.2.5
Please report bugs to the Debian bug tracking system (http://bugs.debian.org/)
or contact the maintainers (at@packages.debian.org).
💡 说明:at 是「一次性定时执行」工具——给一个未来时间点,把一批命令在该时刻跑一次就完事;与 cron 的「周期性调度」互补。at 的执行者是 atd 守护进程,用 at 之前先确认它在跑(3.1 节实测)。
二、命令概览
2.1 语法与测试数据
at [-V] [-q x] [-f file] [-u username] [-mMlbv] timespec ...
at [-V] [-q x] [-f file] [-u username] [-mMlbv] -t time
at -c job ...
at [-V] -l [-o timeformat] [job ...]
atq [-V] [-q x] [-o timeformat] [job ...]
at [ -rd ] job ...
atrm [-V] job ...
batch
参数结构解读:
timespec ...:执行时间,支持相对(now + 1 minute)与绝对(10:30 tomorrow、midnight)两大族写法,3.7 节逐个实测;- 任务命令从标准输入读入(
echo '命令' | at 时间,Ctrl-D 结束交互输入); -f file:从文件读任务命令(3.6 节);-M:不发邮件;-m:即使无输出也发一封执行完毕的邮件;-c job:打印任务全文(3.5 节);-l/atq等价(3.4 节);- 删除用
atrm(或at -rd,3.10 节)。
测试环境准备(演示目录 + atd 启动):
$ mkdir -p /root/demo/at
$ service atd start
* Starting deferred execution scheduler atd
...done.
$ service atd status
* atd is running
2.2 用法提示全量输出(逐行照抄)
at 没有 --help 长说明;给非法选项即触发完整用法:
$ at -Z; echo rc=$?
at: invalid option -- 'Z'
Usage: at [-V] [-q x] [-f file] [-u username] [-mMlbv] timespec ...
at [-V] [-q x] [-f file] [-u username] [-mMlbv] -t time
at -c job ...
at [-V] -l [-o timeformat] [job ...]
atq [-V] [-q x] [-o timeformat] [job ...]
at [ -rd ] job ...
atrm [-V] job ...
batch
rc=1
💡 要点:用法提示把 at、atq、atrm、batch 四个工具的全部形态列在一起——它们本就是同一个包里的「一套工具」:at 提交、atq/-l 查看、atrm 删除、batch 低负载执行。
2.3 版本信息
$ at -V; echo rc=$?
at version 3.2.5
Please report bugs to the Debian bug tracking system (http://bugs.debian.org/)
or contact the maintainers (at@packages.debian.org).
rc=0
版本与 dpkg -l at 一致(3.2.5-1ubuntu1,见第一章)。
三、参数逐项实测
3.1 服务前置:atd 的启动与状态
atd 未运行时 at 命令依然能提交(任务进队列),但永远不会执行,所以先确认服务状态:
$ service atd status; echo rc=$?
* atd is not running
rc=3
$ service atd start; echo rc=$?
* Starting deferred execution scheduler atd
...done.
rc=0
$ service atd status; echo rc=$?
* atd is running
rc=0
$ ps -ef | grep [a]td
daemon 22117 1 0 00:02 ? 00:00:00 /usr/sbin/atd
💡 要点:atd 由 daemon 用户运行、以
/usr/sbin/atd常驻;status 未运行时退出码 3(LSB 约定,与 cron 一致)。开机会不会自启由安装包的默认链接决定(atd 的 LSB 头声明了 rc2~rc5 自启,见本专栏《update-rc.d 命令详解与参数实测(Ubuntu 22.04)》3.1 节)。
3.2 无参数与时间解析失败:Garbled time
不带时间直接调 at,时间解析失败:
$ at; echo rc=$?
Garbled time
rc=1
乱写时间会得到语法定位信息:
$ echo true | at badtime; echo rc=$?
syntax error. Last token seen: b
Garbled time
rc=1
💡 要点:
Garbled time是 at 时间解析的统一报错;syntax error. Last token seen: b会告诉你解析卡在哪个词——排查时间写法时先看这一行。
3.3 提交任务:echo '命令' | at now + 1 minute
标准提交姿势,回显有两行值得逐字解读:
$ echo 'date > /root/demo/at/ran.txt' | at now + 1 minute; echo rc=$?
warning: commands will be executed using /bin/sh
job 1 at Fri Oct 16 00:03:00 2026
rc=0
- warning 行:任务将用 /bin/sh 执行,而不是 bash——语法差异(数组、[[ ]] 等)在这里翻车,脚本复杂时建议任务内容只写一行
bash /path/script.sh; - job 1 at Fri Oct 16 00:03:00 2026:任务号 1;提交发生在 00:02 时段,
now + 1 minute落在下一个整分钟 00:03:00——at 的调度时间会取整到分钟边界。
提交后任务落盘为队列文件(权限 700、属主 root:daemon):
$ ls -l /var/spool/cron/atjobs/
total 4
-rwx------ 1 root daemon 332 Oct 16 00:02 a0000101c7c1c3
💡 要点:队列文件名
a0000101c7c1c3是内部编码(a=队列名),job 号只是对外的编号。不要手工编辑队列文件,一切操作走 at/atrm。
3.4 -l 与 atq:队列查询(列解读与顺序说明)
两者输出完全一致(-l 是 at 的查看模式,atq 是独立命令):
$ at -l
1 Fri Oct 16 00:03:00 2026 a root
$ atq
1 Fri Oct 16 00:03:00 2026 a root
四列含义:任务号、计划执行时间、队列标记(a = at 队列;= 表示正在运行;batch 任务的标记见 3.11 节)、提交用户。多任务时注意顺序——atq 按内部文件序输出,不是按任务号或时间排序:
$ atq
2 Fri Oct 16 02:02:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
1 Fri Oct 16 00:03:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
💡 要点:脚本里统计队列要用排序处理(如
atq | sort -k1n),别假设输出有序。
3.5 at -c N:任务全文解读
-c 打印任务在队列里的真实样子(环境快照 + 命令段),下例为 job 1 的完整输出:
$ at -c 1
#!/bin/sh
# atrun uid=0 gid=0
# mail root 0
umask 22
HOSTNAME=f1034b9326b2; export HOSTNAME
PWD=/; export PWD
HOME=/root; export HOME
SHLVL=0; export SHLVL
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH
cd / || {
echo 'Execution directory inaccessible' >&2
exit 1
}
date > /root/demo/at/ran.txt
逐段解读:
#!/bin/sh+# atrun uid=0 gid=0:任务最终是一段交给 /bin/sh 执行的脚本,由 atd 派生的 atrun 进程以提交者身份(uid=0 root)运行;# mail root 0:邮件策略标记(0 = 仅在有输出时发邮件,-M 提交时该值变化);umask 22+ 环境变量段:提交那一刻的 umask 与关键环境变量被快照进任务——这就是 at「继承提交时环境」的实现方式;PATH 被固定为系统默认值;cd / || { ... }:任务从提交时的当前目录启动(本例提交时在 /),目录不可访问则放弃执行;- 命令段:你提交的原始命令原样保留在最后。
查不存在的任务号:
$ at -c 99999; echo rc=$?
Cannot find jobid 99999
rc=1
💡 要点:排障时先
at -c 任务号看「任务到底会怎么执行」——环境变量、当前目录、执行 shell 全在里面,比猜快得多。
3.6 -f 从文件提交与 -M 禁止发邮件
任务命令较长时写成文件,用 -f 提交;-M 同时声明「不要给我发邮件」:
$ echo 'echo hello from file' > /root/demo/at/job.txt
$ at -f /root/demo/at/job.txt now + 1 hour -M; echo rc=$?
warning: commands will be executed using /bin/sh
job 8 at Fri Oct 16 01:02:00 2026
rc=0
-M 的实测对照:job 8 的命令有 stdout 输出,但在执行后系统日志中没有它的邮件投递尝试记录(对照无 -M 的任务见 3.9 节日志)。
💡 要点:
-M适合「输出无价值」的批量任务;反过来-m是「即使无输出也发一封完成通知」。批处理脚本默认都加-M是良好实践。
3.7 时间格式族:相对、绝对、口语化关键字
一组时间写法的实测(提交发生在 Fri Oct 16 00:02 前后,请对照回显体会「下一个未来时刻」的语义):
$ echo true | at now + 2 hours; echo rc=$?
warning: commands will be executed using /bin/sh
job 2 at Fri Oct 16 02:02:00 2026
rc=0
$ echo true | at 10:30 tomorrow; echo rc=$?
warning: commands will be executed using /bin/sh
job 3 at Sat Oct 17 10:30:00 2026
rc=0
$ echo true | at midnight; echo rc=$?
warning: commands will be executed using /bin/sh
job 4 at Sat Oct 17 00:00:00 2026
rc=0
$ echo true | at noon; echo rc=$?
warning: commands will be executed using /bin/sh
job 5 at Fri Oct 16 12:00:00 2026
rc=0
$ echo true | at teatime; echo rc=$?
warning: commands will be executed using /bin/sh
job 6 at Fri Oct 16 16:00:00 2026
rc=0
$ echo true | at now + 3 days; echo rc=$?
warning: commands will be executed using /bin/sh
job 7 at Mon Oct 19 00:02:00 2026
rc=0
写法归纳:
| 类型 | 写法 | 实测结果与说明 |
|---|---|---|
| 相对 | now + N minutes / hours / days / weeks | 在当前时刻基础上加偏移,落整分钟(02:02、3 天后 00:02) |
| 绝对+日期 | 10:30 tomorrow | 「明天 10:30」;提交时已是 16 日 00:02,tomorrow 解析为 17 日 |
| 关键字 | midnight | 00:00;已过当日 0 点则取次日(17 日 00:00) |
| 关键字 | noon | 12:00(当日 16 日还没到,取当日) |
| 关键字 | teatime | 16:00(下午茶时间,man 页彩蛋,等价于 4pm) |
💡 要点一:所有时间都解析为「下一个未来时刻」——
midnight在 00:02 提交时指的是明天 0 点而非刚刚过去的今天 0 点,10:30 tomorrow同理,容易想当然。💡 要点二:其他常用形态还包括
now + 30 minutes(复数必带 s)、2026-10-17 22:00(ISO 风格)、4pm + 2 days等,规则同源:时间 + 可选日期偏移。
3.8 执行实证:等 65 秒看 atd 真的跑起来
删产物、记录时刻、等 65 秒(覆盖 job 1 的 00:03:00 触发点):
$ rm -f /root/demo/at/ran.txt; date
Fri Oct 16 00:02:27 UTC 2026
(等待 65 秒)
$ date
Fri Oct 16 00:03:32 UTC 2026
$ cat /root/demo/at/ran.txt
Fri Oct 16 00:03:00 UTC 2026
$ ls -l /root/demo/at/
total 8
-rw-r--r-- 1 root root 21 Oct 16 00:02 job.txt
-rw-r--r-- 1 root root 29 Oct 16 00:03 ran.txt
$ atq
2 Fri Oct 16 02:02:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
三重证据:ran.txt 内容是 00:03:00 整(提交时的计划时间被精确执行,秒级不漂移——对比 cron 的整分钟粒度,见 4.1 节对照);文件时间戳 00:03;atq 队列里 job 1 已消失(一次性任务执行完即出队)。
💡 要点:at 执行完的任务文件从 /var/spool/cron/atjobs/ 删除(不像 cron 留有周期性触发),因此 at 的执行痕迹主要靠输出产物与邮件,重要任务请让命令自带日志落盘。
3.9 stdout 与邮件:无 MTA 时的真实行为
任务有 stdout 输出时,atd 会尝试把输出用邮件发给提交者。本环境未安装邮件传输代理(MTA),实测全过程:
$ echo 'echo hello stdout' | at now + 1 minute; echo rc=$?
warning: commands will be executed using /bin/sh
job 9 at Fri Oct 16 00:04:00 2026
rc=0
$ atq
2 Fri Oct 16 02:02:00 2026 a root
9 Fri Oct 16 00:04:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
(等待 65 秒后)
$ date
Fri Oct 16 00:04:37 UTC 2026
$ ls -l /var/mail/root 2>&1
ls: cannot access '/var/mail/root': No such file or directory
$ grep -E "atd|No MTA" /var/log/syslog | tail -3
Oct 15 23:55:01 f1034b9326b2 CRON[22060]: (CRON) info (No MTA installed, discarding output)
Oct 16 00:04:00 f1034b9326b2 atd[22171]: Exec failed for mail command: No such file or directory
判读:job 9 在 00:04:00 执行、产生 stdout,atd 尝试执行 mail 命令投递 → 系统没有 MTA,日志记录 Exec failed for mail command,输出被丢弃,/var/mail/root 从未生成。
💡 要点一:装了 MTA(如 postfix)后,任务 stdout 会投递到
/var/mail/用户名;bash 登录时看到You have new mail提示就是它在提醒你去读(用💡 要点二:让任务「自带日志」是最稳的输出方案:
命令 > /var/log/xxx.log 2>&1;或者提交时加-M明确丢弃输出意图(3.6 节对照实测)。
3.10 atrm:删除队列任务
先看队列,再按任务号删除,删除是静默成功的(rc=0 无输出):
$ echo true | at now + 1 hour; echo rc=$?
warning: commands will be executed using /bin/sh
job 10 at Fri Oct 16 01:04:00 2026
rc=0
$ atq
2 Fri Oct 16 02:02:00 2026 a root
10 Fri Oct 16 01:04:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
$ atrm 2; echo rc=$?
rc=0
$ atq
10 Fri Oct 16 01:04:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
不存在的任务号与正在运行的任务有不同反馈:
$ atrm 99999; echo rc=$?
Cannot find jobid 99999
rc=1
$ atq | awk '{print $1}' | xargs -r atrm
Warning: deleting running job
💡 要点:
Warning: deleting running job出现在删除标记为=(正在运行)的任务时——已启动的进程不会随之消失,atrm 只是撤掉队列记录;at 的等价写法是at -rd 任务号。
3.11 batch:负载空闲时才执行
batch 不是独立守护进程,而是 at 的「低负载队列」:命令相同,只是任务被放进 batch 队列,等系统负载(load average 低于 1.5,可由 atd 的 -l 参数调整)空闲才跑:
$ echo uptime | batch; echo rc=$?
warning: commands will be executed using /bin/sh
job 11 at Fri Oct 16 00:04:00 2026
rc=0
$ atq
10 Fri Oct 16 01:04:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
11 Fri Oct 16 00:04:00 2026 = root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
注意 job 11 的队列标记是 =(正在运行)而非 a——本环境负载极低,batch 任务提交后立即开跑。
💡 要点:batch 适合「跑批但不雪上加霜」的场景(如空闲时跑报表);它同样出现在 atq/atrm 的管理视野里,删除方式相同。
3.12 技术拓展:一次性任务与周期调度的选型对比
「延迟/定时执行」的同类机制横向对比——
| 机制 | 模型 | 精度 | 适用场景 |
|---|---|---|---|
| at | 一次性队列(atd 守护) | 1 分钟 | 今晚只跑一次的维护动作(本文主线) |
| batch | at 的低负载变体 | 1 分钟 | 有负载压力顾虑的跑批 |
| sleep N + cmd | 会话内阻塞延时 | 秒级 | 必须保持会话的短延迟;断连即失 |
| nohup + sleep | 脱离会话的后台延时 | 秒级 | 简单一次性延时,但无队列可查 |
| cron 单字段触发 | 借 cron 表达「只跑一次」 | 1 分钟 | 需事后手工删除表项,易留垃圾表项 |
| systemd-run --on-active | 临时 timer unit | 秒级 | systemd 环境的一次性任务,日志进 journal |
💡 关键差异一句话:at 是「一次性任务」的标准答案——有队列(atq)、可审计(-c)、可撤销(atrm),且不占用会话。本文以 at 为主线(Ubuntu 22.04 开箱自带、POSIX 标准);秒级精度需求或全 systemd 化的机器可考虑 systemd-run,但可读性与可管理性不如 at 直白。
四、实战示例
4.1 场景一:一次性运维任务的标准闭环
「提交 → 确认队列 → 等待 → 验证产物 → 确认出队」五步:
$ echo 'date > /root/demo/at/ran.txt' | at now + 1 minute; echo rc=$?
warning: commands will be executed using /bin/sh
job 1 at Fri Oct 16 00:03:00 2026
rc=0
$ atq
1 Fri Oct 16 00:03:00 2026 a root
$ rm -f /root/demo/at/ran.txt; date
Fri Oct 16 00:02:27 UTC 2026
(等待 65 秒)
$ cat /root/demo/at/ran.txt
Fri Oct 16 00:03:00 UTC 2026
$ atq
2 Fri Oct 16 02:02:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
三重验收:产物内容是计划的 00:03:00 整(秒级不漂移);文件时间戳一致;队列列表里 job 1 已消失(一次性任务执行完即出队)。
4.2 场景二:定点维护窗口(明早、深夜、下班点)
把维护动作排到具体时点,写法即读法。先用无害的验证命令确认时间解析(真实维护命令上线前都建议先走这一步):
$ echo true | at 10:30 tomorrow; echo rc=$?
warning: commands will be executed using /bin/sh
job 3 at Sat Oct 17 10:30:00 2026
rc=0
$ echo true | at midnight; echo rc=$?
warning: commands will be executed using /bin/sh
job 4 at Sat Oct 17 00:00:00 2026
rc=0
时间解析符合预期(明早 10:30、下一个午夜)后,把 true 换成真实维护命令(如 systemctl stop 应用 && tar czf /backup/app.tgz /opt/app、/sbin/poweroff)重新提交即可。提交后立刻复核队列再离开:
$ atq
2 Fri Oct 16 02:02:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
1 Fri Oct 16 00:03:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
4.3 场景三:用文件提交复杂任务(-f + -M)
脚本化场景(CI 清理、临时跑批)推荐文件提交:先写文件、后 at -f、带 -M 静音:
$ echo 'echo hello from file' > /root/demo/at/job.txt
$ at -f /root/demo/at/job.txt now + 1 hour -M; echo rc=$?
warning: commands will be executed using /bin/sh
job 8 at Fri Oct 16 01:02:00 2026
rc=0
文件路径写绝对路径;文件里可放多行命令(按顺序执行,本质是一段 /bin/sh 脚本,环境快照见 3.5 节)。
4.4 场景四:交接前的队列清理
离机前把测试队列清空,避免遗留任务在深夜意外执行:
$ atq
10 Fri Oct 16 01:04:00 2026 a root
7 Mon Oct 19 00:02:00 2026 a root
3 Sat Oct 17 10:30:00 2026 a root
8 Fri Oct 16 01:02:00 2026 a root
5 Fri Oct 16 12:00:00 2026 a root
4 Sat Oct 17 00:00:00 2026 a root
6 Fri Oct 16 16:00:00 2026 a root
$ atq | awk '{print $1}' | xargs -r atrm
Warning: deleting running job
$ atq
Warning: deleting running job 提示某个任务已开跑(= 标记)——已运行的进程需另行处理(kill),队列本身已清空(末次 atq 无输出即空队列)。
五、注意事项与常见问题
Q1:at 与 cron 怎么选? 一句话:at 管一次性,cron 管周期性。详细对照——
| 对比项 | at(本文主角) | cron/crontab |
|---|---|---|
| 执行次数 | 一次,执行完出队 | 按时间表无限重复 |
| 时间写法 | 自然语言风(now + 1 hour、teatime) | 五字段(分 时 日 月 周) |
| 执行者 | atd 守护进程 | cron 守护进程 |
| 精度 | 分钟级(但计划秒点精确执行,实测 00:03:00) | 分钟级,对齐整分钟 |
| 环境继承 | 快照提交时环境(umask/当前目录/关键变量) | 精简环境(PATH 窄、无登录 shell) |
| 典型场景 | 今晚下线一台节点、两小时后触发一次迁移 | 每天凌晨备份、每 5 分钟巡检 |
Q2:任务为什么比我预期晚了几十秒才跑?
atd 按分钟节奏唤醒检查队列,now + 1 minute 解析到下一个整分钟(实测提交于 00:02:27,计划 00:03:00),再叠加唤醒周期,实际启动时间可能比计划时间晚几秒到几十秒。任务里打时间戳(如 date > 执行记录)比掐秒表靠谱。
Q3:任务跑完没收到邮件?
三个检查点:系统是否装了 MTA(本环境实测 /var/mail/root 不存在且日志出现 atd[22171]: Exec failed for mail command: No such file or directory,输出被直接丢弃);提交时是否加了 -M(3.6 节实测可完全禁止投递);任务是否本来就没有 stdout(at 默认只在有输出时发信,-m 可强制发完成通知)。最稳妥的做法是让任务自己写日志文件。
Q4:Garbled time 报错怎么排查?
先看伴随的 syntax error. Last token seen: b 定位到解析失败的词(3.2 节实测)。高频原因:时间单位忘带 s(now + 30 minute 应为 minutes)、把中文标点带进表达式、日期与时间顺序颠倒。不确定时先用 atq 提交一个 echo true | at 你打算写的时间 验证解析结果再换真实命令。
Q5:at 任务的环境和我登录时一样吗?
不完全一样。at -c 任务号 可见真相(3.5 节实测):umask 与提交时刻的关键环境变量被快照保存,当前目录会切回提交时所在目录,但 PATH 被固定为系统默认值,且执行 shell 是 /bin/sh。引用命令时写绝对路径最稳。
Q6:batch 和 at 的区别一句话?
同一个 atd 的两条队列:at 按时间点执行,batch 按系统负载条件执行(load average 降到阈值以下才跑,本环境实测提交即运行、标记为 =)。两者的队列统一在 atq 里查看、atrm 删除。
六、参考链接
- at(1) 手册页(Ubuntu Jammy):https://manpages.ubuntu.com/manpages/jammy/en/man1/at.1.html
- atd(8) 手册页(守护进程与负载阈值参数):https://manpages.ubuntu.com/manpages/jammy/en/man8/atd.8.html
- atrm(1) 手册页:https://manpages.ubuntu.com/manpages/jammy/en/man1/atrm.1.html
- mail(1) 手册页(读取 /var/mail 中的任务输出邮件):https://manpages.ubuntu.com/manpages/jammy/en/man1/mail.1.html
- 关联阅读:本专栏《crontab 命令详解与参数实测(Ubuntu 22.04)》《service 命令详解与参数实测(Ubuntu 22.04)》