- Extract build_job_list helper (shared by show_status/list_logs) - clean_jobs now calls remove_job instead of inline stop/disable/rm - Extract status preamble in write_notify_lines (icon_pre/status_pre) - Replace fragile list-timers tail/awk with systemctl show properties - Combine consecutive sed -i calls into single invocations - Simplify is_manage_mode check to use existing manage_count - Make -o accept optional line count arg (-o 20 or just -o for default 10) - Fix %%s escaping in unit files and document in CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
systab is a single-file Bash script that provides a cron/at/batch-like interface for systemd user timers. It creates, manages, and cleans up systemd .service and .timer unit files in ~/.config/systemd/user/. Managed units are tagged with a # SYSTAB_MANAGED marker comment. Unit filenames use a 6-char hex ID (e.g., systab_a1b2c3.timer) which doubles as the human-facing job identifier.
Running
./systab [OPTIONS]
No build step. The script requires bash, systemctl, and optionally notify-send (for -i) and sendmail/msmtp (for -m).
Architecture
The script has two modes controlled by CLI flags:
-
Job creation (
-t <time> [-c <cmd> | -f <script> | stdin]): Generates a systemd.service+.timerpair with a 6-char hex short ID, reloads the daemon, and enables/starts the timer. Time specs are parsed viaparse_timewhich handles natural language (every 5 minutes),date -drelative/absolute times, and raw systemd OnCalendar values. One-time jobs getPersistent=falseandRemainAfterElapse=no(auto-unload after firing). All jobs log stdout/stderr to the journal viaSyslogIdentifier. Notifications (-idesktop,-memail,-oinclude output) useExecStopPostso they fire on both success and failure with status-aware icons/messages. The-o [N]flag fetches the last N lines of journal output (default 10) and includes them in the notification body (also configurable in edit mode asooro=N). Notification flags are persisted in the service file as a# SYSTAB_FLAGS=comment. -
Management (
-P,-R,-E,-L,-S,-C,-h— mutually exclusive):-P <id>/-R <id>: Pause (stop+disable) or resume (enable+start) a job's timer.-E: Opens$EDITORwith a pipe-separated crontab (ID[:FLAGS] | SCHEDULE | COMMAND). Notification flags are appended to the ID with:(i= desktop,e=addr= email,o= output 10 lines,o=N= output N lines, comma-separated). On save, diffs against the original to apply creates (ID=new), deletes (removed lines), updates (changed schedule/command/flags), and pause/resume (comment/uncomment lines).-L [id] [filter]: Queryjournalctllogs for managed jobs (both unit messages and command output). Optional job ID to filter to a single job.-S [id]: Show timer status viasystemctl, including short IDs and disabled state. Optional job ID to show a single job.-C: Interactively clean up elapsed one-time timers (removes unit files from disk).
Key functions: parse_time (time spec → OnCalendar), _write_unit_files (shared service+timer creation), create_job/create_job_from_edit (thin wrappers), edit_jobs (crontab-style edit with diff-and-apply), get_managed_units (find tagged units by type), clean_jobs (remove elapsed one-time timers), pause_job/resume_job (disable/enable timers), write_notify_lines (append ExecStopPost notification lines), build_flags_string/parse_flags (convert between CLI options and flags format).
Testing
There are no automated tests. Test manually with systemd user timers:
./systab -t "every 5 minutes" -c "echo test"
./systab -S
./systab -L
./systab -P <id>
./systab -R <id>
./systab -C
Notes
- ShellCheck can be used for linting:
shellcheck systab. - Edit mode uses
|as the field delimiter (not tabs or spaces) to allow multi-word schedules. Notification flags use:after the ID (e.g.,a1b2c3:i,o,e=user@host). - Notification flags (
i= desktop,o/o=N= include output,e=addr= email) are persisted as# SYSTAB_FLAGS=...comments in service files and asExecStopPost=lines using$SERVICE_RESULT/$EXIT_STATUSfor status-aware messages. Unit fileprintfformat strings must use%%s(not%s) since systemd expands%sas a specifier before the shell runs. - Journal logs are queried with
USER_UNITORSYSLOG_IDENTIFIERto capture both systemd messages and command output.