计划活动:cron 和 at

作者:John Raithel

Linux 实用工具 cronat 是相关的命令。 cron 实用工具允许您安排重复性任务在任何所需的固定时间间隔执行,而 at 命令允许您指定在某个期望的时间执行一次性操作。 例如,您可以使用 crontab 在每天早上 2 点执行备份,并使用 at 来提醒您当天晚些时候的约会。

使用 crontab

“crontab”一词是“chron table”(时间表)的 Unix 术语。 您需要创建符合所需格式的表格,指定命令和执行命令的时间。 您放入表格中的命令可以是任何可执行程序,例如,/usr/bin 中的命令或您编写的 shell 脚本。 您可以使用 crontab 命令来创建、编辑或列出表格,系统 cron 守护进程读取表格并在指定的时间执行命令。

cron 守护进程

cron 守护进程通常在系统启动时执行,并且不会退出。 在我的 Linux 系统上,cron 守护进程实际上是 Matthew Dillon 的 crond,并在 /etc/rc.d/rc.M 中使用以下行启动

/usr/sbin/crond -l10 >/var/adm/cron 2>&1

在某些 Linux 系统上,使用 Paul Vixie 的 cron 守护进程,在这种情况下,守护进程的名称仅为 cron。 此外,在使用较新版本 init 的系统上,cron 从 /etc/init.d/cron 脚本启动。

您可以使用如下命令检查 cron 守护进程是否在您的系统上运行

$ ps -ax | grep cron
raithel  733  pp0 S   0:00 grep cron
root      25   ?  S   0:00 /usr/sbin/crond -l10

在本例中,我们看到 crond 守护进程确实正在运行。

crontab 表

当 cron 守护进程启动时,它会读取 crontab 目录(通常是 /usr/spool/cron/crontabs)中的各种 crontab 表。 要创建或更改您的 crontab 文件,请使用 crontab 的 -e 选项

$ crontab -e

您将被置于文本编辑器中,其中包含您当前 crontab 文件的副本(如果存在),或者一个空白文件(如果不存在)。 您获得的文本编辑器由您的 VISUAL 环境变量(或 EDITOR,如果未设置 VISUAL)的设置确定,通常是 vi 编辑器(如果您没有另行指定)。

要使用 crontab 计划命令,您必须使用 cron 在 crontab 文件中识别的格式。 此格式不是很直观,所以我创建了一个带有注释掉的标题的 crontab 文件,该标题提供了必要的信息

# minute (0-59),
#    hour (0-23),
#       day of the month (1-31),
#          month of the year (1-12),
#             day of the week (0-6, 0=Sunday),
#                command

每个 crontab 条目都是由这六个字段组成的单行,字段之间用空格分隔。 在第一个字段中使用数字 0 到 59 指定命令要执行的分钟,在第二个字段中使用 0 到 23 指定小时,在第三个字段中使用 1 到 31 指定月份中的日期,在第四个字段中使用 1 到 12 指定年份中的月份,并在第五个字段中使用 0 到 6 指定星期几。 将要执行的命令放在第六个字段中。

乍一看,由于有两个“日期”字段(月份中的日期和星期几),可能显得需要冗余或冲突的信息,但这实际上只是为了允许不同的调度算法。 例如,您可能希望每周二被提醒参加会议,或者每月 15 号领取工资。 在您不使用的日期字段中输入星号 (*)。 如果您希望命令在每月 15 号 以及 每周二都执行,则可以同时使用这两个日期字段。

范围用破折号指定。 如果您想指定月份的第 8 天到第 15 天,请在第三个字段中输入 8-15。 字段中非连续的条目用逗号分隔,因此第三个字段中的 1,15 表示本月的 1 号和 15 号。 要指定字段的所有值,例如每年的每个月,请在该字段中输入星号 (*)。 (请注意,要指定每天,您必须在两个日期字段中都输入 *。)

这是一个带有两个条目的 crontab 文件示例

# minute (0-59),
#   hour (0-23),
#      day of the month (1-31),
#            month of the year (1-12),
#               day of the week (0-6, 0=Sunday)
#                  command
12  4  *     *  *  /usr/local/bin/backup
5   3  10-15 4  *  echo "taxes due" | mail jones

注释后的第一行导致备份脚本在每天凌晨 4:12 执行,第二行导致用户 jones 在四月份的六天内收到邮件消息,以提醒税款到期。 通常,最好在非工作时间(如这些时间)执行 crontab 命令,以减少在正常使用时间对系统负载的任何影响。

如果您没有明确重定向标准错误和标准输出,则当命令执行时,它们会作为 crontab 文件的所有者通过邮件发送给您。 在上面的示例中,如果找不到用户 jones,您将收到输出以及错误消息的邮件。

编辑 crontab 文件后,保存并退出编辑器。 将在 crontab 目录中为您创建一个文件。 例如,root 的 crontab 是文件 /usr/spool/cron/crontabs/root。 系统 cron 守护进程会读取此文件并以内部格式存储,它将保留在此处以定期执行,直到它被更改或删除。

要查看您当前的 crontab 文件,请使用 -l(代表“list”)选项

$ crontab -l

要删除您的文件,请使用

$ crontab -d

如果您是超级用户,则可以使用以下命令删除任何用户的 crontab 文件

# crontab -d username

其中 username 是用户的登录名。

上面讨论的 crontab 命令在我的 Linux 系统上运行良好,并且也应该在 System V 和 BSD Unix 系统上运行。 在其他系统上使用 crontab 或将 crontab 文件移动到其他系统时,需要注意的一件事是,某些 cron 守护进程允许超级用户通过创建 cron.allow 和 cron.deny 文件来限制 crontab 服务。 有关详细信息,请参阅特定系统文档。

此外,大多数版本的 cron 都提供一个 /etc/crontab 文件,该文件在其中有一个额外的字段,即执行命令的用户。 同样,请查看您的 cron 版本的文档以获取更多详细信息。

使用 at

当您想在将来的某个时间执行一次命令或多个命令时,请使用 at

在 Linux 中,at 命令要求 atrun 命令在 root 的 crontab 文件中启动。 许多 Linux 发行版都启用了 at,但有些没有。 要在您的系统上启用 at 实用工具,请成为超级用户并编辑 root 的 crontab 文件

$ su root
Password:
# crontab -e

并添加以下行

* * * * * directory/atrun

其中 directory 是 atrun 可执行文件存储的位置。 在我的系统上是 /usr/lib,因此条目是

* * * * * /usr/lib/atrun

这会导致 atrun 每分钟执行一次。 在添加 atrun 行并保存 crontab 文件后的一分钟左右,将评估并执行任何现有的 at 命令(如果时间合适)。 (在此之前,您可能可以输入 at 命令,但它们永远不会执行。)

为了演示 at 命令,让我们让它在几分钟后在您当前的终端窗口中打印“hello”。 首先,获取时间和您当前的终端设备

$ date
Tue Oct  3 15:33:37 PDT 1995
$ tty
/dev/ttyp2

现在运行 at 命令。 在命令行中指定时间,按 Enter 键,然后输入命令,然后再次按 Enter 键和 Ctrl-D

$ at 15:35
echo "hello" > /dev/ttyp2
^D
Job c00ceb20b.00 will be executed using /bin/sh

at 命令接受输入,直到文件结束字符(通过在行首按 ctrl-D 生成)。 它报告作业号并通知您它将使用 /bin/sh 执行命令。 两分钟后,hello 应该会出现在 /dev/ttyp2 的显示器上。 请注意,您可以输入一系列命令,每行一个命令 — at 将读取每行直到文件结束,并在指定的时间将该文件作为 /bin/sh shell 脚本执行。

假设您想要设置闹钟。 告诉 at 做某事的一种方法是使用相对时间形式,指定相对于 now 的时间。 如果您希望您的计算机在 25 分钟后向您发出哔哔声,请输入

$ at now + 25 minutes
echo ^G > /dev/ttyp4
^D
Job c00ceb7fb.00 will be executed using /bin/sh

您将在 25 分钟后听到哔哔声。 在输入时间规范时,允许很大的灵活性。 例如,at 识别军事时间、“am”和“pm”、月份缩写、包含年份的时间表示法等等。 我的 at 手册页甚至声称 at 接受 teatimenoon 和其他结构。 有关有效时间规范的更多示例,请参阅 at 手册页。

您必须告诉 at 您的 tty 位置,否则它不会将输出发送到您的终端窗口。 如果您愿意,您可以接收邮件

$ at 4:55pm Friday
echo '5 p.m. meeting with Carol' | mail raithel
^D
Job c00ceb7fb.01 will be executed using /bin/sh

要获取您的待处理 at 作业列表,请输入

$ atq

如果您是超级用户,atq 会显示所有用户的待处理 at 作业。 要删除作业,请输入

$ atrm job_number

其中 job_number 是 atq 返回的作业号。 超级用户还可以删除其他用户的作业。

使用 at 的提醒脚本

以下是一个简单的脚本,使我更容易使用 at 向自己发送提醒。 该脚本在指定的时间向用户发送邮件,其中包含在提示符下输入的消息行。 它还显示了一些如何指定时间的语法示例,我发现这对于刷新记忆很有用。

请注意,正如编写的脚本,它要求您在您的主目录中有一个 Msgs 目录。 我创建了 $HOME/Msgs,而不是使用像 /usr/tmp 这样的目录,这样消息在被脚本删除之前会更私密。

#!/bin/sh
echo "Enter your reminder message.
When finished, enter a period (.) at
the beginning of a line and press Enter.
(Or press Ctrl-C or DEL to exit.)"
while :
do
    read MESSAGE
    if [ "$MESSAGE" = "." ]
    then
        break
    else
        echo $MESSAGE > $HOME/Msgs/message.$$
    fi
done
cat << !!
Enter time and day you want to receive
the message, for example:
      0815am Jan 24
      8:15am Jan 24
      now + 1 day
      5 pm Friday
Then press Enter.
!!
read TIME
echo \
  "at $TIME mail $LOGNAME $HOME/Msgs/message.$$"
at $TIME  << !!
mail $LOGNAME < $HOME/Msgs/message.$$
rm -f $HOME/Msgs/message.$$
!!
exit 0
一些最后的想法

不同版本的 Unix 中 crontab 和 at 命令的用户界面非常相似,但底层目录结构、守护进程和访问控制的实现可能有所不同。 请务必查看您的系统文档,以充分利用这些强大命令的各个方面。

crontab 和 at 的用途几乎没有限制,但请允许我提出一些警告。 首先,在启用用户 crontab 和 at 权限时,请考虑安全问题。 显然,心怀不满的同事可能会留下某种“定时炸弹”,其限制仅受其其他权限限制。 许多版本的 crontab 和 at 允许您指定“allow”和“deny”文件来控制哪些用户可以访问这些实用工具。 如果您愿意,您还可以使用 root 的 crontab 来检查和删除用户 crontab(或任何其他文件)。

此外,请彻底调试您的 crontab 文件条目。 检查它们是否工作。 这些条目通常计划在低使用率时段执行,因此您不太可能在当时在场观察它们。

John Raithel 是一位咨询技术作家,专门从事 Unix 操作系统系统和网络管理的文档编写,目前正在为 Silicon Graphics, Inc. 编写万维网和防火墙文档。 他住在美国加利福尼亚州中部海岸的一个小镇上,在那里他玩弄他的 Linux 和 SunOS “迷你网络”。 您可以通过电子邮件 raithel@rahul.net 与他联系。

加载 Disqus 评论