Intermediate · Automation basics: scheduling, archives and shell scripts · topic 35 of 57 · 30 min
One-time jobs with at, and systemd timers
Explanation
at: run something once, later
Sometimes you need a job to run once: restart a service at midnight after a change, or remove a temporary firewall rule in two hours. at does this. It needs the atd service running (systemctl enable --now atd).
$ at now + 2 hours
at> firewall-cmd --remove-port=9000/tcp
at> <Ctrl+D>
job 4 at Mon Oct 19 17:30:00 2026
$ echo "systemctl restart httpd" | at 23:00
$ at 02:00 tomorrow < /root/maintenance.sh
$ atq
4 Mon Oct 19 17:30:00 2026 a root
5 Mon Oct 19 23:00:00 2026 a root
$ at -c 5 | tail -2 # show what job 5 will run
$ atrm 5 # cancel job 5batch is a relative of at: it runs a job when the system load is low. Access to at is controlled by /etc/at.allow and /etc/at.deny, like cron.
systemd timers
A timer unit is a schedule for a service unit. Two small files: backup.service says WHAT to run, and backup.timer says WHEN. Compared with cron, timers log every run in the journal (journalctl -u backup), can run missed jobs after the machine was off (Persistent=true), can add a random delay so 500 servers do not all hit the backup server at once, and use all of systemd's controls (user, resource limits, dependencies).
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup of /etc and /var/www
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup.service every night at 01:30
[Timer]
OnCalendar=*-*-* 01:30:00
Persistent=true
RandomizedDelaySec=10min
[Install]
WantedBy=timers.target# systemctl daemon-reload
# systemctl enable --now backup.timer # enable the TIMER, not the service
Created symlink /etc/systemd/system/timers.target.wants/backup.timer → /etc/systemd/system/backup.timer.
# systemctl list-timers backup.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Tue 2026-10-20 01:34:12 IST 10h left n/a n/a backup.timer backup.service
$ systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
Original form: Mon..Fri *-*-* 09:00:00
Normalized form: Mon..Fri *-*-* 09:00:00
Next elapse: Tue 2026-10-20 09:00:00 IST| OnCalendar value | Meaning |
|---|---|
| daily | Every day at 00:00 |
| hourly | Every hour at minute 0 |
| weekly | Mondays at 00:00 |
| *-*-* 01:30:00 | Every day at 01:30 |
| Mon..Fri 09:00 | Weekdays at 09:00 |
| *-*-01 00:00:00 | The 1st of every month |
Timers can also be relative: OnBootSec=5min runs 5 minutes after boot, OnUnitActiveSec=1h runs again 1 hour after the last run. RHEL itself uses timers, for example dnf-makecache.timer and fstrim.timer; systemctl list-timers --all shows them.
Common mistakes
- Enabling the .service instead of the .timer. The service then runs once at boot, not on schedule.
- Forgetting systemctl daemon-reload after creating the files.
- Using at without atd running: jobs are queued but never run.
- A typo in OnCalendar. Always test it with systemd-analyze calendar.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
One-time jobs with at, and systemd timers · 1/6
echo "systemctl restart httpd" | at 23:00
atq
atrm 5at runs a job once, at a time you choose. It needs the atd service.
Prefer a video by a teacher? Find free videos on “systemd timers tutorial oncalendar persistent at command linux” on YouTube ↗
In real life: Catching up after a power cut in a small-town office
A cooperative society office in a small town in Maharashtra has frequent power cuts at night, so its cron backup at 01:00 was often missed. The admin moved it to a systemd timer with Persistent=true. Now, if the server was off at 01:00, the backup runs as soon as it boots, and journalctl -u backup shows every run and its result.
# journalctl -u backup.service --since yesterday --no-pager | tail -2
Oct 19 06:12:40 coop01 systemd[1]: Starting Nightly backup of /etc and /var/www...
Oct 19 06:13:55 coop01 systemd[1]: backup.service: Deactivated successfully.Practice (0/3 done)
Which command lists jobs waiting to run with at?
You created report.service and report.timer. Which command schedules it?
Create a timer that writes the date and free disk space of / to /var/log/diskcheck.log every 10 minutes, and prove it ran twice.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Archives and compression: tar, gzip, bzip2 and xzAutomation basics: scheduling, archives and shell scripts · same module
- Bash scripts: variables, quoting, arguments and exit codesAutomation basics: scheduling, archives and shell scripts · same module
- Persistent storage and containers as systemd servicesBoot, recovery and containers
- Processes, signals and systemd servicesDevOps: Git, Docker, Kubernetes and CI/CD · Linux for DevOps
- Timers: running code laterFrontend Web Development · JavaScript in the browser: DOM and events
- Linux basics for backend developersBackend Development · Deployment and scaling
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Which service must run for at jobs to execute?
Answer: atd
atd runs at jobs.
What does Persistent=true do in a timer?
Answer: Runs a missed job soon after boot if the machine was off at the scheduled time
It catches up on missed runs.
Which tool checks an OnCalendar expression and shows the next run?
Answer: systemd-analyze calendar
systemd-analyze calendar.
What does OnCalendar=weekly mean?
Answer: Mondays at 00:00
weekly is shorthand for Mon *-*-* 00:00:00.
Without /var/log/journal, where does journald keep logs?Related
Answer: /run/log/journal, lost at reboot
With Storage=auto and no /var/log/journal, logs stay in /run (RAM).
A service shows "active" and "disabled". What happens after a reboot?Related
Answer: It does not start
Disabled means it is not started at boot.
Why does systemctl --user fail after su - webops?Related
Answer: su does not start a full login session with the user's systemd and runtime directory
Log in directly (SSH) as the user.
You started a service with systemctl start, but after a reboot it is not running. What did you forget?Related
Answer: systemctl enable
start runs it now; enable makes it start at boot.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Automation basics: scheduling, archives and shell scripts” before its exam: Archives and compression: tar, gzip, bzip2 and xz, Bash scripts: variables, quoting, arguments and exit codes, Bash scripts: conditions, loops and safe habits.
- Module 7 exam: Automation basics · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Boot, recovery and containers. 57 topics left in the course before the final exam.