Scheduling Tasks#

Linux systems come with a number of tools for scheduling tasks on a system. The traditional way to do this is to use the cron daemon for persistant scheduled jobs or the at command for non-persistant jobs. The new alternative is to use systemd timers as it is more flexible and more reliable.

Scheduled commands with cron#

Cron is a system for scheduling tasks to be run periodically with a precission of one minute. Multiple implementations are available, but most Linux distributions use the anacron implementation. The name is derived from the name of the greek god Cronos, the god of time.

Using cron itself is simple, but defining the tasks is a bit more involved as you need to figure out the correct scheduling syntax. Let start with option -l to list all available tasks that are defined for the current user.

Listing cron jobs for current user#
$ crontab -l
no crontab for user01

With the option -e you can edit the cron file as cron makes a copy of the crontab file and lets you edit it via the editor specified in the EDITOR environment variable or specified as the system default as a fallback.

Editing the crontab file for the current user#
$ crontab -e

Warning

The option -r will remove all tasks from the crontab file without prompting for confirmation. Some users confuse this with the -e option which will edit the crontab file or to view the crontab file in read-only mode.

Removing all tasks from the crontab file can be done with the option -r.

Remove all cron jobs for current user#
$ crontab -r

All actions are performed on the crontab file for the current user, but with the following option -u <user> you can also perform them on the crontab file for another user.

List cron jobs for specific user#
# crontab -u user01 -l

Beside the crontab files per user in /var/spool/cron there is also a cron file for the system cron daemon in /etc/crontab and a cron file for the root user in /etc/cron.d. Taking a closer look at /etc/crontab you can see that the system cron daemon is using the cron file for the root user and can run commands under a different user.

$ cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

Crontab settings per user are located in /var/spool/cron and are similar to the crontab file for the system cron daemon, but without the option to switch to a different user. For all these values you can combine them as single value, a list of values or a range of values, but also divide them to get a matching schedule. Some examples are listed in the table below.

Job definition

Description

1 2 3 4 5

Every Friday (5) the is on April (4) 3th at 2:01am

30 4 * * *

Every day at 4:30am

30 4-6 * * *

Every day at 4:30am, 5:30am and 6:30am

30 4-8/2 * * *

Every day at 4:30am, 6:30am, 8:30am

30 4,6,8 * * *

Every day at 4:30am, 6:30am and 8:30am

0 15,20 * */2 1-5

Every workday during an even month at 15:00 and 20:00

*/10 8-16,22 * * *

Every 10 minutes between 8am and 5pm and between 10pm and 11pm

Scheduled commands with at#

at [-V] [-q queue] [-f file] [-mMlv] timespec...
at [-V] [-q queue] [-f file] [-mMkv] [-t time]
at -c job [job...]
atq [-V] [-q queue]
at [-rd] job [job...]
atrm [-V] job [job...]
batch
at -b

Systemd timers#

Systemd Timers

List all active timers#
# systemctl list-timers
NEXT                        LEFT          LAST                        PASSED       UNIT                         ACTIVATES
Wed 2021-11-17 02:00:00 CET 15s left      Wed 2021-11-17 01:50:34 CET 9min ago     sysstat-collect.timer        sysstat-collect.service
Wed 2021-11-17 03:19:18 CET 1h 19min left Wed 2021-11-17 01:22:46 CET 36min ago    dnf-makecache.timer          dnf-makecache.service
Wed 2021-11-17 21:30:46 CET 19h left      Tue 2021-11-16 11:17:42 CET 14h ago      systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Thu 2021-11-18 00:00:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago logrotate.timer              logrotate.service
Thu 2021-11-18 00:00:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago mlocate-updatedb.timer       mlocate-updatedb.service
Thu 2021-11-18 00:00:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago unbound-anchor.timer         unbound-anchor.service
Thu 2021-11-18 00:07:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago sysstat-summary.timer        sysstat-summary.service
Mon 2021-11-22 01:07:18 CET 4 days left   Mon 2021-11-15 01:00:34 CET 2 days ago   fstrim.timer                 fstrim.service
n/a                         n/a           Mon 2021-11-15 00:00:35 CET 2 days ago   rdiff-backup.timer           rdiff-backup.target

9 timers listed.
Pass --all to see loaded but inactive timers, too
Stop timer#
$ systemctl --user stop schedule-test.timer
$ systemctl --user disable schedule-test.timer
$ systemctl --user stop schedule-test.service
$ systemctl --user disable schedule-test.service
$ systemctl --user daemon-reload
$ systemctl --user reset-failed
[Unit]
Description=Schedule a message every 1 minute
RefuseManualStart=no  # Allow manual starts
RefuseManualStop=no   # Allow manual stops

[Timer]
#Execute job if it missed a run due to machine being off
Persistent=true
#Run 120 seconds after boot for the first time
OnBootSec=120
#Run every 1 minute thereafter
OnUnitActiveSec=60
#File describing job to execute
Unit=schedule-test.service

[Install]
WantedBy=timers.target

Transient timer units#

Like

create a transient timer unit to run a command#
# systemd-run --on-active=30 /bin/touch /tmp/foo

Execute

create a transient timer unit to run a command#
# systemd-run --on-active="1h 5m" --unit app.service