Scheduling one-time tasks with 'at'

There are times when you need to execute a given task just once at a later time on a Unix-like operating system. cron might be the obvious choice for this, however, for a one-time task that would require either an elaborate schedule part (e.g. 05 04 12 08 05) or cleaning it up after the task is done, to ensure it runs just once. For example, the next time that the cron schedule "05 04 12 08 05" would match the actual date/time (Friday, August 12, 04:05) after 2016 would be 2022, so it would not really be a one-time task.

Fortunately, there is a tool that does just that (and does it well) - executes a given task just once on a given time in the future, and there is no cleanup afterwards necessary. It is called at.

Syntax

at allows for a fairly diverse ways of specifying the date and time to run the task. The main rule here is that the date must be specified after the time. You're also not restricted to a rigid 'HH:mm dd.mm[.yyyy]' syntax, as at understands offsets (+, next) and verbal specifications (e.g. midnight, noon, teatime, now, which would be at 00:00, 12:00, 16:00 and now respectively). AM/PM can also be added to the time specification.

$> at 18:29 tomorrow
$> at 03:00 +2 [minutes/hours/days/months/weeks/years]

at does not absolutely require the full date/time to be specified. Instead, you can specify only the part that is different than the current date/time. For example, at fri would schedule a job for next friday at the same time as the moment the command was executed.

One way of specifying what to run is to pipe it to at:

echo "It's 04:05" | at 04:05 tomorrow

If it's a longer input, you can enter an interactive prompt after you specify the time/date pair, which will wait for your input of commands to run. Ctrl+D (while at the beginning of the line) finishes and saves the input:

$> at 04:05 tomorrow
warning: commands will be executed using /bin/sh
at> echo "It's 04:05"
at> echo "and it's tomorrow too"
at> <EOT>
job 1 at Wed May 24 04:05:00 2016

at can also read commands from a file, instead of standard input:

$> echo "I'm in a file" > job.sh
$> at -f job.sh fri
warning: commands will be executed using /bin/sh
job 3 at Fri May 24 04:08:00 2016
$> atq
3       Fri May 24 04:08:00 2016 - user
$> at -c 3
#!/bin/sh
[truncated]
echo "I'm in a file"

atq can be used to see already scheduled jobs for the current user (or all users, if executed with root). at -c <job number> would list the complete script that would be executed.

The job will be executed in the same working directory and with the same environment variables as when it was scheduled.

After the job is done, the particular user should receive a email with standard error and standard output from the task, if there is any. /usr/sbin/sendmail will be used to send the email.

To remove a scheduled job, atrm <job number> can be used:

$> atq
1       Wed May 24 04:05:00 2016 - user
$> atrm 1
$> atq
$>

There is another similar command to at, called batch. The difference is that the given job is executed when the system load drops below a certain value.

Access control

There is a way to restrict, which users are allowed to run at (and batch), by using /etc/at.allow and /etc/at.deny, just like with cron: if at.allow exists, it is used to determine, which users are allowed, and at.deny is ignored in that case. Otherwise everyone can use at, except for those in at.deny. Root can always use at.

Summary

at allows to schedule, view and remove one-time tasks, and is more suitable for such tasks than cron. It has a flexible way of specifying of what to run and when to run the tasks, as well as access control.