In the past we have written about scheduling jobs with cron and more recently with systemd timer units. These are very robust methods for scheduling jobs in Linux. Both of the above mentioned methods are great for scheduling recurring jobs. What if you want to schedule a script or simple command to run just one time? Enter the at command.

The at command is a great command line tool. The authors designed it for the sole purpose of allowing a user to schedule a single run of a job at some future time. In this article we will show you the basics of how to use at to schedule a job for later execution, list the scheduled jobs, delete jobs, and set the nice value for scheduled jobs . We will also touch on the batch command, which is part of the at suite.

Schedule a Job Using at Command

At the most basic level, using at is simple. Simply call the utility followed by the time and date you want the job to run. This will drop you to the "at" prompt. Here you will type your commands or script to call. When you have entered all your commands, hit CTRL+D to exit and schedule the job.

Animated GIF showing the basic use of the Linux at command to schedule a job

In the above example we scheduled the rsync.sh script to run at 9:30 PM on May 11 2019. The <EOT> denotes where I pressed CTRL+D to exit the at prompt and queue the job.

Alternatively, you can pipe the job to at using the echo command. This is cleaner in my opinion, but I suppose it is more prone to errors.

$ echo "/bin/bash ~/scripts/rsync.sh" | at 3:00 AM 
 warning: commands will be executed using /bin/sh
 job 35 at Sat May 11 03:00:00 2019

Methods of Specifying Time

There are many ways to specify time while using the at utility. You can use common terms like noon, midnight, next week, next Friday or even tomorrow. When using casual terms that do not include a time (i.e. tomorrow) it will use the current time. So if the current time was 9:30 PM and you specified "tomorrow" it would set the job for 9:30 PM the next day.

Animated gif showing the AT command using casual time specifications

Since I don't use the at command often, I like to always specify exact times. In my opinion it keeps me honest and helps avoid any confusion.

You can find the exact definition of the time specification in /usr/share/doc/at/timespec on Fedora systems. If you are having trouble finding the file, try:

cat $(find / -name timespec 2>/dev/null)

About warning: commands will be executed using /bin/sh

Every time you run the at command this concerning, and some think scary, error message will greet you.

warning: commands will be executed using /bin/sh

This is hard coded into the utility and will display no matter what shell you are using. This is simply an informational message letting you know that the utility will execute the job using /bin/sh no matter what your default shell is or the shell you used to schedule the job. If you are executing a bash script, just be sure to have the proper shebang (#!/bin/bash) to ensure the script runs with the correct shell.

Controlling Nice Values with Queue Designations

You can control the niceness or nice value of a scheduled job by using a queue designation.

nice is a program found on Unix and Unix-like operating systems such as Linux. It directly maps to a kernel call of the same name. nice is used to invoke a utility or shell script with a particular CPU priority, thus giving the process more or less CPU time than other processes. A niceness of -20 is the highest priority and 19 is the lowest priority.

-Wikipedia Nice (Unix)

Valid queue designations range from a to z, with a being the default queue and b being reserved for batch jobs. Jobs scheduled with a higher queue designation run with an increased niceness. As a result they will run with a lower CPU priority than other processes.

Here is an example of scheduling a job with a increased niceness. Most importantly this is useful when a system has several high CPU demand processes running and you do not want to interrupt those processes.

$ echo "nicetest.sh" | at -q h noon

In the above example we used the letter h as the queue designation. This can be shown using the atq command, which we explain in-depth later in this tutorial.

Using Batch to Run Jobs when System Load Levels Permit

The batch command is part of the at utility suite. They both work similarly, but batch does not accept a time parameter. It will ONLY run the job when system load averages drop below 0.8 by default, or the value specified by atd.

Animated GIF showing how to use the batch command to schedule jobs to run when system load levels permit

You can change the default load averages by editing the configuration for atd. On Fedora systems this is in /etc/sysconfig/atd. On Ubuntu systems this is in the /lib/systemd/system/atd.service file.

List Queued Jobs Using atq

The atq command is part of the at utility suite. It shows you a listing of the scheduled jobs, and their corresponding job number.

$ atq
 45    Sat May 11 16:00:00 2019 a savona
 43    Mon May 13 21:43:00 2019 a savona
 48    Sat May 11 12:00:00 2019 h savona
 39    Mon May 13 21:40:00 2019 a savona

The data fields in the atq command output are:

  1. Job Number
  2. Day
  3. Month
  4. Day of Month
  5. Time
  6. Year
  7. Queue designation [a-z] (a is default, b is reserved for batch jobs)
  8. User who scheduled job

Running atq as a non-root user will show you which jobs your account has scheduled. If you run it as root (or using sudo), it will show you all the jobs scheduled for ALL users.

Example of atq output run as root:

# atq
 45    Sat May 11 16:00:00 2019 a savona
 43    Mon May 13 21:43:00 2019 a savona
 47    Sat May 11 12:00:00 2019 a test
 46    Sun Jun  2 23:00:00 2019 a savona

NOTE: You can also use "at -l" (which is an alias of atq) to list the scheduled jobs, in addition to atq.

Printing the Contents of Scheduled Jobs

Listing the jobs with atq shows you a lot of information. However, it doesn't show what the actual content of the job. To see what the job will execute, we can use the -c (cat) option to print the contents to standard output.

[savona@putor ~]$ at -c 43
 #!/bin/sh
 atrun uid=1000 gid=1000
 mail savona 0
 umask 2
 SHELL=/bin/bash; export SHELL
...OUTPUT TRUNCATED...

Deleting Scheduled Jobs Using atrm

If you want to delete a scheduled job, knowing how to list them is important. You can only delete a job by specifying the job number which is shown in the atq output or at time of scheduling.

To delete jobs we can use the atrm command. Once you know the job number you want to delete, simply run atrm followed by the job number.

Animated GIF showing how to use the atq and atrm commands to list and delete queued jobs

NOTE: You can also use "at -d" (which is an alias of atrm) to delete scheduled jobs in addition to atrm.

Securing Use of the at Command

You can control permissions to schedule jobs with two files, the /etc/at.allow file and /etc/at.deny. Most modern Linux systems come with a blank /etc/at.deny file which allows all users to queue jobs with the at command.

If the file /etc/at.allow exists, only usernames mentioned in it are allowed to use at.
If /etc/at.allow does not exist, /etc/at.deny is checked, every username not mentioned in it is then allowed to use at.
An empty /etc/at.deny means that every user is allowed use these commands, this is the default configuration.
If neither exists, only the superuser is allowed use of at.

- at Man Page

To deny a user permission to use the at command, simply enter their username in the /etc/at.deny file. You can do this by opening the file in your favorite editor, or using sudo with the tee command.

$ echo "test" | sudo tee -a /etc/at.deny

Now if the user tries to schedule a job with at, they will get a notification that they do not have permission to use it.

[test@putor ~]$ at noon
 You do not have permission to use at.

Conclusion

In this article we covered the use of the at suite of utilities, including at, atq, batch and atrm. You should now be comfortable scheduling one time jobs using the at command. You can read the man pages for more information and always feel free to drop a note in the comments.

Resources