您可能已经使用过 cron 来安排任务,然后发现该任务只需要运行一次。一个常见的例子是授予供应商对生产服务器的临时 SSH 访问权限以进行故障排除。您可能会为他们的 IP 地址开放防火墙,并计划几个小时后移除该规则。

问题在于很容易忘记。生产环境问题层出不穷,优先级也会变化,不知不觉中,那条临时的防火墙规则在应该被移除很久之后仍然留在那里。

这正是 at 命令的用武之地,它允许您安排一次性任务在未来的特定时间运行,非常适合那些需要稍后自动恢复的临时更改。虽然大多数 Linux 管理员都知道 cron,但许多人忽略了 at,因为 cron 获得了最多的关注。

在本指南中,我们将解释什么是 at,如何安排一次性任务,以及如何在 Linux 中管理排队中的 at 作业。

Linux 中的 at 命令是什么

at 命令允许您安排一条命令或脚本在未来的特定时间只运行一次。您告诉它何时运行,提供命令,剩下的交给 Linux 处理。

在幕后,at 将作业放入队列,而一个名为 atd 的后台服务会检查该队列,并在预定时间到达时运行作业。

这就是 at 与 cron 的不同之处。

cron 旨在处理重复性任务,例如每晚运行备份或每周一生成报告;而 at 旨在处理只需发生一次的一次性任务。

例如,您可以使用 at 来:

  • 在今晚维护窗口期间稍后重启服务。
  • 几小时后删除临时文件。
  • 在故障排除结束后重新启用防火墙规则。
  • 在一天结束时关闭测试服务器。
  • 在特定时间给自己发送提醒或通知。

可以这样理解:

  • 如果任务需要每天运行,请使用 cron。
  • 如果任务需要在特定时间只运行一次,请使用 at。

一个好的经验法则是:如果您发现自己创建了一个 cron 作业,然后在它运行后立即将其删除,那么该任务本来就应该使用 at 来安排。

安装 at 并启动 atd 服务

在许多 Linux 发行版中,at 包默认未安装,因此您需要先安装它。

sudo apt install at         [On Debian, Ubuntu and Mint]
sudo dnf install at         [On RHEL/CentOS/Fedora and Rocky/AlmaLinux]
sudo apk add at             [On Alpine Linux]
sudo pacman -S at           [On Arch Linux]
sudo zypper install at      [On OpenSUSE]    
sudo pkg install at         [On FreeBSD]

这将安装 at 命令以及相关实用工具,如 atq 和 atrm。它还安装了 atd 服务,该服务负责在正确的时间运行已安排的作业。

安装完成后,请确保服务正在运行,并配置为重启后自动启动:

sudo systemctl enable --now atd
sudo systemctl status atd

输出:

● atd.service - Deferred execution scheduler
     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; preset: enab>
     Active: active (running) since Thu 2026-06-18 10:54:36 IST; 23s ago
 Invocation: 9656ef36140d404eae309ec9642e402a
       Docs: man:atd(8)
   Main PID: 4804 (atd)
      Tasks: 1 (limit: 8683)
     Memory: 256K (peak: 2M)
        CPU: 8ms
     CGroup: /system.slice/atd.service
             └─4804 /usr/sbin/atd -f

如果您看到上述内容,说明服务工作正常,已准备好处理已安排的作业。

如果 atd 已停止或未运行,您使用 at 安排的任何作业都将保留在队列中且永远不会执行,这是新用户认为 at 命令不起作用的最常见原因之一,因此在排查问题时,首先检查服务状态总是值得的。

使用 at 安排一次性任务

让我们回到向供应商授予服务器临时 SSH 访问权限的例子,假设您已经为其 IP 开放了防火墙。

在 Ubuntu/Debian (ufw) 上:

sudo ufw allow from 203.0.113.50 to any port 22

在 RHEL/Rocky Linux (firewalld) 上:

sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="203.0.113.50" port port="22" protocol="tcp" accept'

与其依赖自己记住稍后移除该规则,您可以立即使用 at 安排移除操作。

例如,要在晚上 10:00 移除防火墙规则:

at 22:00

您将进入交互式提示符,可以在其中输入想要运行的命令:

在 Ubuntu/Debian 上:

warning: commands will be executed using /bin/sh
at Thu Jun 18 22:00:00 2026
at> ufw delete allow from 203.0.113.50 to any port 22
at> <EOT>
job 3 at Thu Jun 18 22:00:00 2026

在 RHEL/Rocky Linux 上:

warning: commands will be executed using /bin/sh
at Thu Jun 18 22:00:00 2026
at> firewall-cmd --remove-rich-rule='rule family="ipv4" source address="203.0.113.50" port port="22" protocol="tcp" accept'
at> <EOT>
job 3 at Thu Jun 18 22:00:00 2026

按下 Ctrl+D 后,at 会保存作业并显示一个作业编号。在此示例中,job 3 已安排在晚上 10:00 运行。

一个有用的功能是,如果指定的时间今天已经过去,at 会自动将作业安排在明天同一时间。

在一行中安排作业

如果您已经知道要运行的命令,可以跳过交互式提示符,直接将命令发送给 at。

Ubuntu/Debian:

echo "ufw delete allow from 203.0.113.50 to any port 22" | at 22:00

RHEL/Rocky Linux:

echo "firewall-cmd --remove-rich-rule='rule family=\"ipv4\" source address=\"203.0.113.50\" port port=\"22\" protocol=\"tcp\" accept'" | at 22:00

firewalld 示例中包含转义的双引号 (\")。这些反斜杠防止 shell 过早结束引号字符串,并确保整个命令正确传递给 at。

以下是单行版本发生的事情:

  • echo "..." 以纯文本形式打印命令。
  • 管道 (|) 将该文本发送到 at。
  • at 22:00 读取命令并将其安排在晚上 10:00 运行。

这种方法在脚本、自动化任务或希望快速安排作业而不进入交互式提示符时特别有用。

使用自然时间表达式安排 Linux 任务

at 命令最有用的功能之一是它能够理解人类友好的时间表达式。您无需计算确切时间,只需简单地告诉 Linux 相对于当前时间何时希望作业运行即可。

例如,如果供应商只需要未来两小时的 SSH 访问权限,您可以安排防火墙规则在该时间段后自动移除。

echo "ufw delete allow from 203.0.113.50 to any port 22" | at now + 2 hours

输出:

job 4 at Thu Jun 18 14:30:00 2026

at 命令理解几种自然时间表达式:

at now + 30 minutes 
at now + 2 hours 
at now + 1 day 
at noon at midnight 
at noon tomorrow 
at 5pm tomorrow 
at 08:30 AM

使用 atq 查看已安排的作业

在使用 at 安排一个或多个作业后,最好验证它们是否确实已在队列中等待运行。

atq 命令显示当前用户的所有待处理作业。

atq

输出:

3       Thu Jun 18 22:00:00 2026 a root
4       Thu Jun 18 14:30:00 2026 a root

每一行代表一个已安排的作业。

3 Thu Jun 18 22:00:00 2026 a root

让我们分解第一个条目:

  • 3 是作业 ID。
  • Thu Jun 18 22:00:00 2026 是预定的执行时间。
  • a 是队列名称(at 使用的默认队列)。
  • root 是安排该作业的用户。

每当您想确认任务是否已正确安排时,atq 命令都非常有用。

例如,在创建一个用于移除临时防火墙规则的作业后,您可以运行:

atq

并在授予供应商访问您的服务器之前,验证清理作业是否在队列中等待。

如果 atq 没有返回任何输出,则当前您的用户账户没有待处理的已安排作业。

atq

使用 atrm 移除作业

如果一个作业正停留在队列中,而您改变了主意——也许供应商提前完成了工作,您希望立即关闭防火墙而不是等待——atrm 可以在其运行前取消它。

atrm job-number

用您在 atq 输出中看到的数字替换 job-number,这是我们将在本指南中用于表示需要您自行填写的值的角度括号约定。

atrm 4

如果执行成功,则不会有任何输出。紧接着再次运行 atq,该任务编号应该会从列表中消失。请记住,如果您取消了任务,仍然需要手动关闭规则,atrm 仅删除计划的任务,而不会移除防火墙更改本身。

结论

at 命令是那些在您真正需要它之前容易被忽视的 Linux 工具之一。每当您有一个需要在特定时间仅运行一次的任务时,它通常比创建临时 cron 作业更好的选择。