Skip to main content

Commands and Management

Learning Focus

By the end of this lesson you will be fluent in every command needed to manage timer units — from creation to cleanup, including schedule validation, log inspection, user timers, and bulk operations.

Standard Workflow

Every time you create or modify a timer unit, follow this sequence:

standard-workflow.sh
# 1. Create/edit the .timer and .service files
sudo nano /etc/systemd/system/myjob.timer
sudo nano /etc/systemd/system/myjob.service

# 2. Tell systemd to re-read unit files
sudo systemctl daemon-reload

# 3. Enable on boot and start now
sudo systemctl enable --now myjob.timer

# 4. Verify it appears in the timer list
systemctl list-timers myjob.timer --no-pager

# 5. Test the service manually
sudo systemctl start myjob.service

# 6. Check logs
journalctl -u myjob.service -n 20 --no-pager

systemctl — Timer Management

Starting and Stopping

CommandDescription
sudo systemctl start myjob.timerStart the timer immediately
sudo systemctl stop myjob.timerStop the timer (won't disable on boot)
sudo systemctl restart myjob.timerStop and restart the timer

Enabling and Disabling

CommandDescription
sudo systemctl enable myjob.timerEnable on boot (does not start)
sudo systemctl enable --now myjob.timerEnable on boot AND start now
sudo systemctl disable myjob.timerDisable on boot (does not stop)
sudo systemctl disable --now myjob.timerDisable AND stop
Enable the .timer, NOT the .service

Always enable the .timer, never the .service. Enabling the service directly would run it once at boot — not on a schedule.

# ✅ Correct
sudo systemctl enable --now myjob.timer

# ❌ Wrong — runs once at boot, no scheduling
sudo systemctl enable --now myjob.service

Checking Status

CommandDescription
systemctl status myjob.timer --no-pagerTimer status: next run, last trigger
systemctl status myjob.service --no-pagerService result: exit code, output
systemctl is-active myjob.timerReturns active or inactive
systemctl is-enabled myjob.timerReturns enabled or disabled
status-examples.sh
# Check when it will next fire
systemctl status myjob.timer --no-pager

# Check what happened on the last run
systemctl status myjob.service --no-pager

# Quick check in scripts
if systemctl is-active --quiet myjob.timer; then
echo "Timer is running"
fi

Reloading

CommandDescription
sudo systemctl daemon-reloadRe-read all unit files from disk
Always Reload After Changes

If you edit a unit file and forget daemon-reload, systemd uses the old version. This is the #1 cause of "I changed the config but nothing happened."


Listing and Discovery

List All Timers

list-timers.sh
# List all timers with their schedule info
systemctl list-timers --all --no-pager
example-output.txt
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-03-02 02:15:00 UTC 2h 14min left Sun 2026-03-01 02:15:03 UTC 21h ago wp-backup.timer wp-backup.service
Mon 2026-03-02 00:05:00 UTC 4min left Mon 2026-03-02 00:00:01 UTC 58s ago health-check.timer health-check.service
Mon 2026-03-02 03:00:00 UTC 2h 59min left Sun 2026-03-01 03:01:15 UTC 20h ago certbot-renew.timer certbot-renew.service

Column meanings:

ColumnMeaning
NEXTNext scheduled fire time
LEFTTime remaining until NEXT
LASTLast time the timer fired
PASSEDTime since LAST
UNITThe timer unit name
ACTIVATESThe service it triggers

List Enabled Timers

list-enabled.sh
systemctl list-unit-files --type=timer --state=enabled

Show Timer Properties

show-properties.sh
# Machine-readable properties (for scripting)
systemctl show myjob.timer -p NextElapseUSecRealtime -p LastTriggerUSec -p Unit -p Triggers

# Show the unit file content
systemctl cat myjob.timer
systemctl cat myjob.service

# Show where the unit file is stored
systemctl show -p FragmentPath myjob.timer

Show Dependencies

dependencies.sh
systemctl list-dependencies myjob.timer
systemctl show -p Triggers myjob.timer

Testing the Service Immediately

test-now.sh
# Run the service without waiting for the timer
sudo systemctl start myjob.service

# Check the result
journalctl -u myjob.service -n 20 --no-pager

systemd-analyze — Schedule Validation

Validate OnCalendar Expressions

validate-schedule.sh
# Show the next 5 fire times
systemd-analyze calendar --iterations=5 'Mon..Fri 06:00'

# Validate common patterns
systemd-analyze calendar --iterations=3 'daily'
systemd-analyze calendar --iterations=3 '*:0/5'
systemd-analyze calendar --iterations=3 '*-*~1 00:00:00'
systemd-analyze calendar --iterations=5 '09,21:00'
systemd-analyze calendar --iterations=3 '*-*-* 08..20:0/10'

Verify Unit Files

verify-units.sh
sudo systemd-analyze verify /etc/systemd/system/myjob.timer
sudo systemd-analyze verify /etc/systemd/system/myjob.service

# Verify both at once
sudo systemd-analyze verify /etc/systemd/system/myjob.{timer,service}

No output means no errors. Errors print the exact line and directive:

error-example.txt
/etc/systemd/system/myjob.timer:5: Unknown key 'OnCalander' in section 'Timer'

Security Audit

security-audit.sh
systemd-analyze security myjob.service

Score: 0.0 = fully sandboxed, 10.0 = no sandboxing. Aim for below 3.0.

Boot Impact

boot-impact.sh
systemd-analyze blame | grep timer
systemd-analyze critical-chain timers.target

journalctl — Log Management

Service Logs (Most Important)

The .service produces the real output. The .timer only logs activation events.

CommandDescription
journalctl -u myjob.serviceAll logs from the service
journalctl -u myjob.service -n 50Last 50 lines
journalctl -u myjob.service -fFollow live output (like tail -f)
journalctl -u myjob.service --since "1 hour ago"Logs from the last hour
journalctl -u myjob.service --since todayToday's logs
journalctl -u myjob.service --since "2026-03-01" --until "2026-03-02"Date range
journalctl -u myjob.service -o json-prettyJSON format
journalctl -u myjob.service -p errErrors only

Timer Logs

timer-logs.sh
# When the timer fired
journalctl -u myjob.timer --since today --no-pager

Combined View

combined-logs.sh
# Both timer and service logs, interleaved by time
journalctl -u myjob.timer -u myjob.service --since today --no-pager

Log Priority Levels

LevelFlagMeaning
Emergency-p emergSystem unusable
Alert-p alertImmediate action required
Critical-p critCritical conditions
Error-p errError conditions
Warning-p warningWarning conditions
Notice-p noticeNormal but significant
Info-p infoInformational
Debug-p debugDebug-level

User Timer Management

User timers run without root privileges:

CommandDescription
systemctl --user daemon-reloadReload user unit files
systemctl --user enable --now myjob.timerEnable and start user timer
systemctl --user disable --now myjob.timerDisable and stop user timer
systemctl --user status myjob.timerCheck status
systemctl --user list-timers --no-pagerList user timers
journalctl --user -u myjob.serviceView user service logs
user-timer-workflow.sh
mkdir -p ~/.config/systemd/user/
# Place .timer and .service in ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now my-timer.timer

Persistence After Logout

enable-linger.sh
# Keep user timers running after logout
sudo loginctl enable-linger "$USER"

# Check status
loginctl show-user "$USER" | grep Linger

# Disable
sudo loginctl disable-linger "$USER"

Persistent State Management

persistent-state.sh
# Clear stored timer state (reset Persistent catch-up tracking)
sudo systemctl clean --what=state myjob.timer

# Show timer timestamps (last trigger, next elapse)
systemctl show myjob.timer -p LastTriggerUSec -p NextElapseUSecRealtime

Bulk Operations

Enable Multiple Timers

bulk-enable.sh
for unit in /etc/systemd/system/*.timer; do
name=$(basename "$unit")
sudo systemctl enable --now "$name"
done

Health Check All Timers

bulk-health.sh
systemctl list-timers --all --no-pager --no-legend | while read -r next left last passed unit activates rest; do
echo "=== $unit ==="
systemctl status "$unit" --no-pager 2>/dev/null | head -5
echo
done

Full Cleanup

cleanup.sh
sudo systemctl disable --now myjob.timer
sudo rm /etc/systemd/system/myjob.timer
sudo rm /etc/systemd/system/myjob.service
sudo systemctl daemon-reload
sudo systemctl reset-failed

Quick Command Reference

TaskCommand
Reload unit filessudo systemctl daemon-reload
Start timersudo systemctl start myjob.timer
Stop timersudo systemctl stop myjob.timer
Enable + startsudo systemctl enable --now myjob.timer
Disable + stopsudo systemctl disable --now myjob.timer
Check timer statussystemctl status myjob.timer --no-pager
Check service resultsystemctl status myjob.service --no-pager
List all timerssystemctl list-timers --all --no-pager
Follow live logsjournalctl -u myjob.service -f
Last N log linesjournalctl -u myjob.service -n 50
Errors onlyjournalctl -u myjob.service -p err
Validate schedulesystemd-analyze calendar --iterations=5 'EXPR'
Verify unit syntaxsudo systemd-analyze verify myjob.timer
Show unit contentsystemctl cat myjob.timer
Test service nowsudo systemctl start myjob.service
Security auditsystemd-analyze security myjob.service
Reset timer statesudo systemctl clean --what=state myjob.timer
Reset failedsudo systemctl reset-failed

Key Takeaways

  • Always daemon-reload after editing unit files.
  • Enable the .timer, not the .service.
  • Use systemd-analyze calendar to validate every schedule before deploying.
  • Use systemd-analyze verify to catch syntax errors before runtime.
  • Check both .timer status (next/last run) and .service status (exit code, logs).
  • Use systemctl list-timers --all for a system-wide overview.
  • User timers need loginctl enable-linger for persistence after logout.

What's Next

  • Practical Examples — 27 complete, copy-paste-ready examples covering every timer pattern.