Scheduling work.
cron, at, and systemd timers, and when to use which.
logadmin1 needs a daily backup, a weekly cleanup, and a one-shot update tonight. Three scheduling tools, one for each job, all logging so you know they ran.
logadmin1 has three jobs that need to run with nobody watching. The /etc backup from the backup-pipeline ticket, every night at 2:30. A sweep of tarballs older than 14 days, every Sunday at 4. And a one-off dnf upgrade tonight at 11, once, never again. Three schedules, and the twist in the ticket is that each one wants a different tool. That is not overkill. It is the right answer to three different shapes of problem.
Recurring and simple is cron. One time in the future is at. Modern, with calendar syntax and the ability to catch up a run it missed while the box was powered off, is a systemd timer. And each of them can drop a tagged line into the journal, which is the only part the audit will actually check.
The ticket
sudo dnf install -y cronie at sudo systemctl enable --now crond atd systemctl is-active crond atd
Concept review. Three tools, three jobs.
man 5 crontab man at man systemd.timer
A cron line has five time fields followed by the command. The order is the part people get wrong, so read it left to right every time.
* * * * * command | | | | | | | | | +- day of week (0-7, Sunday is 0 or 7) | | | +--- month (1-12) | | +----- day of month (1-31) | +------- hour (0-23) +--------- minute (0-59)
There are shortcut strings too: @daily, @weekly, @monthly, @reboot.
cron for the daily backup
Edit root’s crontab and add one line. The percent signs inside the date command must be escaped with a backslash, because cron treats a bare percent as a newline.
sudo crontab -e # add this line (minute hour day month weekday): 30 2 * * * /usr/bin/tar -czf /srv/backups/etc-$(date +\%Y\%m\%d).tar.gz /etc/ 2>/dev/null && logger -t backup "daily etc backup completed" sudo crontab -l sudo journalctl -u crond -n 20
logger -t backup writes a tagged line into the journal, which is how you prove the job ran.
at for the one-shot update
at reads the command from stdin, so piping is the cleanest form. Queue it, then confirm with atq.
echo "dnf upgrade -y && logger -t maint 'security upgrade complete'" | sudo at 23:00 # warning: commands will be executed using /bin/sh # job 1 at Wed Jul 15 23:00:00 2026 sudo atq # 1 Wed Jul 15 23:00:00 2026 a root sudo at -c 1 # dumps the full script that will run # sudo atrm 1 # remove it if plans change
Time formats at understands include 23:00, now + 2 hours, midnight, and 3pm Friday. If you give it a time that already passed today, it schedules for tomorrow, which surprises people at least once.
A systemd timer for the weekly cleanup
A timer is two unit files that share a name: a .service that does the work and a .timer that says when. The service is Type=oneshot because it runs and exits rather than staying up.
sudo bash -c 'cat > /etc/systemd/system/backup-cleanup.service << "EOF" [Unit] Description=Delete backup tarballs older than 14 days [Service] Type=oneshot ExecStart=/usr/bin/find /srv/backups -name "*.tar.*" -mtime +14 -delete ExecStartPost=/usr/bin/logger -t backup-cleanup "completed" EOF' sudo bash -c 'cat > /etc/systemd/system/backup-cleanup.timer << "EOF" [Unit] Description=Run backup cleanup every Sunday at 4am [Timer] OnCalendar=Sun *-*-* 04:00:00 Persistent=true [Install] WantedBy=timers.target EOF' sudo systemctl daemon-reload sudo systemctl enable --now backup-cleanup.timer systemctl list-timers backup-cleanup.timer # NEXT LEFT UNIT ACTIVATES # Sun 2026-07-19 04:00:00 EDT 3 days backup-cleanup.timer backup-cleanup.service # test the service now rather than waiting until Sunday to find a typo sudo systemctl start backup-cleanup.service sudo journalctl -u backup-cleanup.service -n 10
Persistent=true means if the machine was off when the timer should have fired, it runs at the next boot instead of silently skipping.cron time patterns worth reading aloud
0 0 * * * daily at midnight */15 * * * * every 15 minutes 0 9 * * 1-5 9 AM Monday through Friday 0 0 1 * * first of every month at midnight 0 22 * * 0,6 10 PM on Saturday and Sunday
The systemd equivalents use OnCalendar: --* 05:00:00 is daily at 5, Mon --* 09:00:00 is Mondays at 9, and Mon..Fri --* 17:30:00 is weekdays at 5:30 PM.
Exam questions
Write the command first.
Q1. Schedule /usr/local/bin/backup.sh to run every Monday at 2:30 AM as the current user.
Q2. Schedule a one-time job to run dnf -y update tonight at 10:30 PM, and verify it is queued.
Q3. Create a systemd timer that runs /usr/local/bin/cleanup.sh every day at 5:00 AM, enabled on boot.
Answers.
# A1: crontab -e, then add: 30 2 * * 1 /usr/local/bin/backup.sh # order is minute hour day month weekday; 1 is Monday # A2 echo "dnf -y update" | sudo at 22:30 sudo atq # A3: two unit files, cleanup.service (Type=oneshot) and cleanup.timer # timer: OnCalendar=*-*-* 05:00:00 and Persistent=true, then: sudo systemctl daemon-reload sudo systemctl enable --now cleanup.timer
Final checklist: confirm everything works
If every check passes, the ticket is done.
# 1. daily 2:30 backup in root's crontab sudo crontab -l # 2. 11 PM upgrade queued sudo atq # 3. Sunday cleanup timer enabled systemctl list-timers backup-cleanup.timer # 4. all three test-fired without errors # 5. all three exam commands written from scratch # 6. tracker entry checked off
Reply to logadmin1: all three scheduled. Daily backup via cron, weekly cleanup via a systemd timer, tonight’s upgrade via at. Each logs to the journal with its own tag.