在 Linux 系统中,如果只需要执行一次性任务,使用 cron 可能会显得过于复杂。 此时,at
系列命令就能派上用场! 若希望进程仅在系统资源空闲时运行,则可以考虑使用 batch
命令。
Linux 任务调度方法
cron
守护进程维护着一个 任务列表,这些任务会在特定的时间自动运行。 它们在后台运行,为需要重复执行的任务提供了极大的灵活性。 不论是需要每小时、每天、每月还是每年执行任务,cron
都可以满足需求。
然而,若只需运行一次性任务,cron
则不太适用。 虽然可以在 cron
中设置任务,但任务完成后,还需记得返回并删除 crontab 条目,这未免有些不便。
幸运的是,在 Linux 世界中,如果遇到难题,很可能其他人也曾遇到过。 鉴于类 Unix 操作系统悠久的历史,很有可能已经存在针对此问题的解决方案。
而对于上述问题,答案就是 at
命令。
安装 at
命令
我们需要在 Ubuntu 18.04 和 Manjaro 18.1.0 上安装 at
命令(在 Fedora 31 上已预装)。
在 Ubuntu 上安装,请使用以下命令:
sudo apt-get install at
安装完成后,可以使用以下命令启动 at
守护进程:
sudo systemctl enable --now atd.service
在 Manjaro 上,可以使用以下命令安装 at
:
sudo pacman -Sy at
安装完成后,输入以下命令启动 at
守护进程:
sudo systemctl enable --now atd.service
在任何发行版上,都可以键入以下命令以确保 atd
守护进程正在运行:
ps -e | grep atd
如何交互式使用 at
命令
要使用 at
命令,必须指定任务运行的日期和时间。 at
提供了多种灵活的方式来定义日期和时间,我们将在后文中详细介绍。
即使是以交互方式使用 at
命令,也必须预先提供日期和时间。 如果在命令行中不包含日期和时间,或输入的内容不是日期或时间,at
会响应“乱码时间”,如下所示:
at
at banana
日期和时间可以是明确的,也可以是相对的。 例如,若希望在一分钟后执行命令,at
知道“现在”是什么意思,因此可以使用 now
并加上一分钟,如下所示:
at now + 1 minute
at
会打印一条消息和一个 at
提示符,并等待输入要调度的命令。 请注意以下消息:
它会提示您启动一个 sh
shell 实例,并在其中 运行命令。 请注意,您的命令不是在 Bash shell 中执行,而是与 sh
shell 兼容,但后者功能集较为简单。
如果命令或脚本尝试使用 Bash 提供的功能或工具,而 sh
没有,则命令将会失败。
可以很容易地测试命令或脚本是否能在 sh
中运行。 使用 sh
命令启动 sh
shell:
sh
命令提示符变为美元符号 ($
),现在可以运行命令并验证它们是否能正确运行。
要返回 Bash shell,请键入 exit
命令:
exit
您不会从命令中看到任何标准输出或错误消息,因为 sh
shell 是作为后台任务启动的,并且在没有任何类型的屏幕界面下运行。
命令的任何输出(包括好坏)都会通过电子邮件发送给您。 它通过内部邮件系统发送给运行 at
命令的用户。 这意味着您必须设置和配置该内部邮件系统。
许多(大多数)Linux 系统没有内部邮件系统,因为它们很少被使用。 通常使用 sendmail 或 postfix 等系统。 如果您的系统没有内部邮件系统,可以让脚本写入文件或将输出重定向到文件以进行日志记录。
如果命令没有生成任何标准输出或错误消息,则您不会收到电子邮件。 许多 Linux 命令通过静默表示成功,因此在大多数情况下,您不会收到邮件。
现在,可以开始在 at
中输入命令了。 在此示例中,我们将使用名为 sweep.sh
的小脚本文件,该文件会删除 *.bak
、*.tmp
和 *.o
文件。 输入命令的路径,如下所示,然后按 Enter。
将出现另一个命令提示符,可以添加任意数量的命令。 通常情况下,将命令放入单个脚本中,并从 at
中调用该脚本更为方便。
按 Ctrl+D 表示您已完成添加命令。 该组合键在程序中表示
作业执行后,键入以下命令来检查内部邮件:
如果没有邮件,则必须假设成功。 当然,在这种情况下,可以检查 *.bak
、*.tmp
和 *.o
文件是否已被删除以确认命令有效。
键入以下内容以再次运行整个过程:
at now + 1 minute
一分钟后,键入以下内容来重新检查邮件:
是的,我们有邮件了! 要阅读第一条消息,请按 1,然后按 Enter。
我们收到了一封来自 at
的电子邮件,因为脚本中的命令生成了错误消息。 在此示例中,没有要删除的文件,因为当我们在之前运行脚本时,它已经删除了这些文件。
按 D+Enter 删除电子邮件,按 Q+Enter 退出邮件程序。
日期和时间格式
在使用 at
命令时,可以灵活使用各种时间格式。 以下是一些示例:
在上午 11:00 运行:
at 11:00 AM
在明天上午 11:00 运行:
at 11:00 AM tomorrow
在下周的今天上午 11:00 运行:
at 11:00 AM next week
在下周的此时运行:
at next week
在下周五上午 11:00 运行:
at 11:00 AM next fri
在下周五的此时运行:
at next fri
在下个月的这天上午 11:00 运行:
at 11:00 AM next month
在特定日期的上午 11:00 运行:
at 11:00 AM 3/15/2020
在现在起 30 分钟后运行:
at now + 30 minutes
在现在起 2 小时后运行:
at now + 2 hours
在明天此时运行:
at tomorrow
在星期四的此时运行:
at thursday
在凌晨 12:00 运行:
at midnight
在下午 12:00 运行:
at noon
如果身处英国,您甚至可以安排命令在下午茶时间(下午 4 点)运行:
at teatime
查看作业队列
可以键入 atq
命令来查看已计划的作业队列,如下所示:
对于队列中的每个命令,atq
会显示以下信息:
- 作业编号
- 指定的日期
- 计划的时间
- 作业被放入队列的时间。队列标记为“a”、“b”等。 使用
at
安排的普通任务会进入队列“a”,而通过batch
安排的任务(稍后会介绍)会进入队列“b”。 - 安排作业的用户。
在命令行中使用 at
不必以交互方式使用 at
;也可以在命令行中使用。 这使得在脚本内部使用变得更加容易。
可以使用管道将命令传递给 at
,如下所示:
echo "sh ~/sweep.sh" | at 08:45 AM
作业会被 at
接受并调度,作业编号和执行日期会像之前一样报告。
将 at
与命令文件结合使用
还可以将一系列命令存储在文件中,然后将其传递给 at
。 这可以是命令的纯文本文件,而不必是可执行脚本。
可以使用 -f
(文件)选项将文件名传递给 at
:
at now + 5 minutes -f clean.txt
如果将文件重定向到 at
,也可以获得相同的结果:
at now + 5 minutes < clean.txt
从队列中删除已计划的作业
要从队列中删除已计划的作业,可以使用 atrm
命令。 如果想先查看队列以找到要删除的作业编号,可以使用 atq
。 然后,将作业编号与 atrm
一起使用,如下所示:
atq
atrm 11
atq
如何查看作业的详细信息
如前所述,可以将作业安排在很远的未来。 有时,您可能会忘记作业的具体内容。 atq
命令显示队列中的作业,但不显示它们将要执行的操作。 若要查看作业的详细信息,可以使用 -c
(cat)选项。
首先,使用 atq
找到作业编号:
atq
现在,我们将使用带有 -c
选项的作业编号 13:
at -c 13
以下是我们获得有关此作业的信息的详细分析:
- 第一行:表明命令将在
sh
shell 下运行。 - 第二行:显示命令将以用户 ID 1000 和组 ID 1000 运行,这些是运行
at
命令的用户的 ID 值。 - 第三行:接收任何电子邮件的收件人。
- 第四行:用户掩码为 22。 这是用于设置此
sh
会话中创建的任何文件的默认权限的掩码。 从 666 中减去掩码,得到 644(rw-r--r--
的八进制等价物)。 - 其余数据:大部分是环境变量。
- 测试结果。 测试会检查是否可以访问执行目录。 如果不能,则会引发错误并放弃作业执行。
- 要执行的命令。 这些命令会被列出,并显示计划脚本的内容。 请注意,虽然我们上述示例中的脚本是为在 Bash 下运行而编写的,但它仍然会在
sh
shell 中执行。
batch
命令
batch
命令 类似于 at
命令,但有三个显著区别:
- 只能以交互方式使用
batch
命令。 batch
命令不是将作业安排在特定时间执行,而是将它们添加到队列中,当系统的平均负载低于 1.5 时,batch
命令会执行这些作业。- 由于上述原因,永远不会使用
batch
命令指定日期和时间。
使用 batch
命令时,可以直接通过名称调用它,无需命令行参数,如下所示:
batch
接下来,就像使用 at
命令一样添加任务。
控制对 at
命令的访问
at.allow
和 at.deny
文件控制谁可以使用 at
系列命令。 它们位于 /etc
目录中。 默认情况下,仅存在 at.deny
文件,它是在安装 at
时创建的。
以下是它们的工作原理:
at.deny
:列出不能使用at
来调度作业的应用程序和实体。at.allow
:列出可以使用at
来调度作业的人员。 如果at.allow
文件不存在,则at
仅使用at.deny
文件。
默认情况下,任何人都可以使用 at
。 如果想限制谁可以使用它,可以使用 at.allow
文件来列出可以使用的人。 这比将不能使用 at
的每个人添加到 at.deny
文件更容易。
at.deny
文件如下所示:
sudo less /etc/at.deny
该文件列出了操作系统中不能使用的组件。 出于安全考虑,许多组件被阻止使用,因此您不应从文件中删除任何内容。
现在,我们将编辑 at.allow
文件。 我们将添加 dave
和 mary
,并且不允许其他人使用 at
。
首先,输入以下命令:
sudo gedit /etc/at.allow
在编辑器中,我们添加两个名称,如下图所示,然后保存文件。
如果其他人尝试使用 at
,他会被告知没有权限。 例如,假设名为 eric
的用户键入以下命令:
at
他将被拒绝,如下图所示。
请注意,eric
不在 at.deny
文件中。 将任何人放入 at.allow
文件后,其他所有人都会被拒绝使用 at
的权限。
一次性任务的理想选择
如您所见,at
和 batch
都是只运行一次的任务的理想选择。 再次快速回顾:
- 当需要执行非常规的任务时,可以使用
at
来安排它。 - 如果只想在系统负载足够低时运行任务,请使用
batch
。