<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Automation on 0xMax42 - Flatfile purist. Autodidact. Systems thinker.</title><link>https://0xMax42.io/en/categories/automation/</link><description>Recent content in Automation on 0xMax42 - Flatfile purist. Autodidact. Systems thinker.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sat, 24 May 2025 21:30:00 +0000</lastBuildDate><atom:link href="https://0xMax42.io/en/categories/automation/index.xml" rel="self" type="application/rss+xml"/><item><title>Creating systemd Timers via CLI – Simple, Fast, Hassle-Free</title><link>https://0xMax42.io/en/p/creating-systemd-timers-via-cli-simple-fast-hassle-free/</link><pubDate>Sat, 24 May 2025 21:30:00 +0000</pubDate><guid>https://0xMax42.io/en/p/creating-systemd-timers-via-cli-simple-fast-hassle-free/</guid><description>&lt;img src="https://0xMax42.io/p/systemd-timer-per-cli-erstellen-einfach-schnell-nervenschonend/systemd-timer-cover.webp" alt="Featured image of post Creating systemd Timers via CLI – Simple, Fast, Hassle-Free" /&gt;&lt;p&gt;If you&amp;rsquo;ve ever tried writing systemd timers by hand, you know: it&amp;rsquo;s not exactly fun. Between &lt;code&gt;.service&lt;/code&gt; and &lt;code&gt;.timer&lt;/code&gt; files, path syntax, and &lt;code&gt;OnCalendar&lt;/code&gt; expressions, it&amp;rsquo;s easy to get lost. That’s why I built a small tool: &lt;code&gt;systemd-timer&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-does-it-do"&gt;What does it do?
&lt;/h2&gt;&lt;p&gt;It’s simple: You call a CLI command, provide a few arguments, and the tool writes the appropriate &lt;code&gt;.service&lt;/code&gt; and &lt;code&gt;.timer&lt;/code&gt; files for you — with logging, dependencies, and all the systemd details you’d otherwise have to remember. No copy-pasting templates, no typos, no wondering whether it’s &lt;code&gt;WantedBy=timers.target&lt;/code&gt; or not.&lt;/p&gt;
&lt;h2 id="why-not-just-use-cron"&gt;Why not just use &lt;code&gt;cron&lt;/code&gt;?
&lt;/h2&gt;&lt;p&gt;Sure, &lt;code&gt;cron&lt;/code&gt; works. But systemd has some clear advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better logging (including to file)&lt;/li&gt;
&lt;li&gt;Easier integration with other services (like waiting for network)&lt;/li&gt;
&lt;li&gt;Works per-user (no root needed)&lt;/li&gt;
&lt;li&gt;Everything stays in one ecosystem: systemd&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This CLI lowers the entry barrier while still encouraging &amp;ldquo;proper&amp;rdquo; systemd usage.&lt;/p&gt;
&lt;h2 id="what-can-systemd-timer-do"&gt;What can &lt;code&gt;systemd-timer&lt;/code&gt; do?
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Generates &lt;code&gt;.service&lt;/code&gt; + &lt;code&gt;.timer&lt;/code&gt; unit files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports &lt;code&gt;--user&lt;/code&gt; timers (great for desktop or containers)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Logging to file via &lt;code&gt;--logfile&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Standard options like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--exec&lt;/code&gt;, &lt;code&gt;--calendar&lt;/code&gt;, &lt;code&gt;--after&lt;/code&gt;, &lt;code&gt;--environment&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--description&lt;/code&gt;, &lt;code&gt;--output&lt;/code&gt;, &lt;code&gt;--dry-run&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CLI built with Cliffy, typed with Deno&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Platform-independent install via shell script&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-quick-example"&gt;A quick example
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemd-timer create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --exec &lt;span class="s2"&gt;&amp;#34;/usr/local/bin/backup.sh&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --calendar &lt;span class="s2"&gt;&amp;#34;Mon..Fri 02:00&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --description &lt;span class="s2"&gt;&amp;#34;Backup Job&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --user &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --logfile &lt;span class="s2"&gt;&amp;#34;/var/log/backup.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This creates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.config/systemd/user/backup.service&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/systemd/user/backup.timer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To activate:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl --user daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl --user &lt;span class="nb"&gt;enable&lt;/span&gt; --now backup.timer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="one-liner-install"&gt;One-liner install
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://git.0xmax42.io/maxp/systemd-timer/raw/branch/main/scripts/install.sh &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The script auto-detects your architecture (amd64/arm64), fetches the right binary, and verifies it via SHA256. And yes, you can inspect the code before piping it into your shell.&lt;/p&gt;
&lt;h2 id="development--testing"&gt;Development &amp;amp; testing
&lt;/h2&gt;&lt;p&gt;The tool is written entirely in TypeScript with Deno, strictly typed and covered by tests. The core is modular enough that you could use it as a library if needed.&lt;/p&gt;
&lt;p&gt;Run tests with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deno task &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;systemd-timer&lt;/code&gt; isn’t a monster with 1000 options — it’s just what you want when you need a clean way to run small systemd-timed tasks without rewriting the same files over and over. It’s aimed at people who prefer declarative setups over improvisation.&lt;/p&gt;
&lt;p&gt;Source code, releases, and more:
👉 &lt;a class="link" href="https://git.0xmax42.io/maxp/systemd-timer" target="_blank" rel="noopener"
&gt;git.0xmax42.io/maxp/systemd-timer&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>