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.