Weight: 4
Goal: Use cron or anacron to run jobs at regular
intervals, and use at to run jobs at a specific time.
Linux has two distinct scheduling systems. Know the difference:
| System | Purpose |
|---|---|
| cron (and anacron) | Run jobs repeatedly on a schedule (every hour, every day at 3 a.m., every Monday, etc.). |
| at (and batch) | Run a job once, at a specified future time. |
A third tool, systemd timers, is a modern replacement for both. The exam expects awareness of it.
cron is a daemon (crond or
cron) that wakes up every minute, checks all the system’s
crontabs, and runs whatever jobs are due. It is the standard way to
schedule recurring tasks on Linux.
There are two kinds of crontabs:
/var/spool/cron/ (location varies by distro: also
/var/spool/cron/crontabs/). Managed only with the
crontab command — never edit these files
directly./etc/crontab and the
files in /etc/cron.d/. Edited as text by root.* * * * * command-to-run
│ │ │ │ │
│ │ │ │ └── day of week (0–7, where 0 and 7 are Sunday)
│ │ │ └───── month (1–12)
│ │ └──────── day of month (1–31)
│ └─────────── hour (0–23)
└────────────── minute (0–59)
/etc/crontab and /etc/cron.d/*)Same as above plus a user field before the command:
* * * * * user command-to-run
This is the single biggest difference to remember for the exam.
| Symbol | Meaning | Example |
|---|---|---|
* |
every value | * in hour = every hour |
, |
list of values | 0,15,30,45 = four times an hour |
- |
range | 1-5 in day-of-week = Mon–Fri |
/ |
step | */10 in minute = every 10 minutes |
Instead of five fields, you can write:
| Shortcut | Meaning |
|---|---|
@reboot |
Once at system startup. |
@yearly / @annually |
Once a year (0 0 1 1 *). |
@monthly |
Once a month (0 0 1 * *). |
@weekly |
Once a week (0 0 * * 0). |
@daily / @midnight |
Once a day (0 0 * * *). |
@hourly |
Once an hour (0 * * * *). |
0 3 * * * /usr/local/bin/backup.sh
# Every day at 03:00.
*/15 * * * * /usr/bin/check-disk.sh
# Every 15 minutes.
0 9-17 * * 1-5 /usr/local/bin/business.sh
# Every hour from 09:00 to 17:00, Monday through Friday.
30 2 1 * * /usr/local/bin/monthly.sh
# At 02:30 on the 1st of every month.
0 0 * * 0 /usr/local/bin/weekly.sh
# At midnight every Sunday.
Watch out: if you set both day-of-month and day-of-week, cron runs the job when either matches (it’s an OR, not an AND).
crontabcrontab -l # list YOUR crontab
crontab -e # edit YOUR crontab (opens $EDITOR)
crontab -r # remove YOUR crontab — no confirmation, careful!
crontab -i -r # remove with confirmation
crontab file.txt # replace YOUR crontab with the contents of file.txt
crontab -l -u alice # root: list alice's crontab
crontab -e -u alice # root: edit alice's crontabcrontab -e is the right way to edit — it does syntax
checks and reloads cron when you save.
/etc/cron.*/ Directories/etc/crontab is the main system crontab. A typical
Debian/Ubuntu version looks like this:
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
This invokes run-parts, which runs every executable
script inside the listed directories:
| Directory | Runs |
|---|---|
/etc/cron.hourly/ |
Once an hour. |
/etc/cron.daily/ |
Once a day. |
/etc/cron.weekly/ |
Once a week. |
/etc/cron.monthly/ |
Once a month. |
If you want a job to run on one of these schedules and you don’t need precise timing, just drop an executable script into the right directory. No crontab entry needed.
/etc/cron.d/A directory of additional system crontab files. Each file uses the
same format as /etc/crontab (with the user
field). Packages drop their cron jobs here so they don’t have to modify
/etc/crontab.
cron jobs run with a minimal environment. Common gotchas:
PATH is short — usually just
/usr/bin:/bin. Use full paths in your commands.HOME is set to the user’s home.DISPLAY,
TERM, etc. are absent./dev/null if you don’t want
that.You can override variables at the top of a crontab:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
0 3 * * * /usr/local/bin/backup.sh
MAILTO="" disables mail entirely.
MAILTO=user sends output to that user.
cron.allow and cron.denyYou can restrict which users may use crontab:
| File | Effect |
|---|---|
/etc/cron.allow |
If this file exists, only the users listed here may use cron. |
/etc/cron.deny |
If cron.allow does not exist, users
listed here are denied. |
Rules:
cron.allow exists, only it matters;
cron.deny is ignored.at uses the same model with /etc/at.allow
and /etc/at.deny (see section 9).
cron only runs jobs at the time they are scheduled. If
the machine is off at that time, the job is
skipped. That’s fine for servers, but a problem for
laptops and desktops.
anacron solves this. It is designed for systems that are not running 24/7. It checks whether a job has run within its specified period; if not, it runs the job now.
/etc/anacrontabFormat (note: different from cron):
period delay job-id command
1 5 cron.daily run-parts /etc/cron.daily
7 25 cron.weekly run-parts /etc/cron.weekly
@monthly 45 cron.monthly run-parts /etc/cron.monthly
| Field | Meaning |
|---|---|
period |
How often the job should run, in days. @monthly is a
shortcut. |
delay |
Minutes to wait after anacron starts before running the job (so multiple jobs don’t all run at once). |
job-id |
Unique tag, used to record when the job last ran. |
command |
The command to run. |
/var/spool/anacron/.delay.Most modern distributions use both:
cron
runs the daily/weekly/monthly jobs.anacron runs them later —
typically right after the next boot.That’s why entries in /etc/crontab often look like:
test -x /usr/sbin/anacron || ( cd / && run-parts /etc/cron.daily )
— meaning “only run from cron if anacron isn’t installed.”
anacron itself does not run continuously; it is invoked by cron at boot or daily.
at and
batch: One-Off Jobsat schedules a command to run once at a
future time.
$ at 22:00
warning: commands will be executed using /bin/sh
at> /usr/local/bin/backup.sh
at> <Ctrl-D>
job 4 at Mon May 12 22:00:00 2026You can also feed a script via stdin:
$ at 22:00 < script.sh
$ echo "/usr/local/bin/cleanup.sh" | at now + 5 minutesat understandsat 10:30
at noon
at midnight
at teatime # 16:00
at 10am tomorrow
at 23:00 next monday
at now + 2 hours
at now + 30 minutes
at 14:00 2026-12-31
| Command | Action |
|---|---|
atq (or at -l) |
List pending jobs. |
atrm 4 (or at -d 4) |
Remove job number 4. |
at -c 4 |
Show the content of job 4. |
batchbatch is at’s sibling. It runs the command
as soon as system load drops below a threshold
(traditionally a load average under 0.8), instead of at a specific
time.
$ batch
at> /usr/local/bin/big-job.sh
at> <Ctrl-D>atSame model as cron:
/etc/at.allow — if present, only listed users may use
at./etc/at.deny — used only if at.allow does
not exist.at jobs are stored in /var/spool/at/ (or
/var/spool/atjobs/). You don’t usually look in there.
The exam expects awareness of systemd timers as a modern alternative to cron.
Key points:
.timer file) triggers a
corresponding service unit (.service
file).journalctl, more flexible time syntax, and the
ability to be persistent (re-run missed jobs, like anacron).systemctl list-timers # show all active timers
systemctl status mytask.timer
systemctl enable --now mytask.timerYou don’t need to write timer files for the exam, just know they exist and replace cron.
Files and directories:
/etc/crontab/etc/cron.d//etc/cron.hourly/, /etc/cron.daily/,
/etc/cron.weekly/, /etc/cron.monthly//etc/cron.allow, /etc/cron.deny/var/spool/cron/ (user crontabs — do not edit by
hand)/etc/anacrontab/var/spool/anacron//etc/at.allow, /etc/at.deny/var/spool/at/Commands:
crontab (with -l, -e,
-r, -u)cron / crond (the daemon)at, atq, atrm,
batchanacronsystemctl list-timers (awareness)What are the five time fields of a user crontab, in order? minute, hour, day of month, month, day of week.
What extra field does /etc/crontab have that
a user crontab doesn’t? The user field
(between time fields and the command).
How do you write “every 15 minutes” in cron?
*/15 * * * *.
What does @daily mean in a crontab?
Same as 0 0 * * * — once a day at midnight.
Where are user crontabs stored, and should you edit them
directly? In /var/spool/cron/ (or
/var/spool/cron/crontabs/). No — always
use crontab -e.
How do you list another user’s crontab as root?
crontab -l -u username.
What is the difference between cron and anacron? cron runs jobs at exact times and skips them if the machine is off; anacron runs jobs that were missed once the machine is back on. anacron is for desktops/laptops that aren’t on 24/7.
What are the fields of
/etc/anacrontab? period (days), delay (minutes),
job-id, command.
You want a one-time command to run tomorrow at 3 a.m.
Which tool do you use, and how? at. Example:
at 03:00 tomorrow.
What is batch? Like
at, but runs the command when the system load drops below a
threshold instead of at a specified time.
How do you list pending at jobs and remove
one? atq to list,
atrm <jobnumber> to remove.
If /etc/cron.allow exists with one user
“alice” in it, who can use cron? Only alice (and root).
Everyone else is denied. /etc/cron.deny is ignored when
cron.allow exists.
A cron job runs but can’t find the python3
command, which works fine in your shell. Why? cron’s
PATH is minimal. Either use the full path
(/usr/bin/python3) or set PATH= at the top of
the crontab.
Where does the output of a cron job go by
default? It is emailed to the owning user.
Redirect to a file or /dev/null to suppress.
A script must run once every hour without precise
scheduling. What is the simplest way? Drop an executable script
into /etc/cron.hourly/.