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 低负载执行。

Linux命令Linux系统UbuntuUbuntu 22.04命令行进程管理2026/10/16

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 日
关键字midnight00:00;已过当日 0 点则取次日(17 日 00:00)
关键字noon12:00(当日 16 日还没到,取当日)
关键字teatime16: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 提示就是它在提醒你去读(用 mail 命令查看)。没装 MTA 时这封信永远不存在。

💡 要点二:让任务「自带日志」是最稳的输出方案:命令 > /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 分钟今晚只跑一次的维护动作(本文主线)
batchat 的低负载变体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 删除。

六、参考链接