<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Colas.Nahaboo.net - linux</title>
    <subtitle>Colas Nahaboo personal site, with discussions about programming code, web and computing topics, surfing and SUPing, and various musings.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://colas.nahaboo.net/tags/linux/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://colas.nahaboo.net"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-08-10T00:00:00+00:00</updated>
    <id>https://colas.nahaboo.net/tags/linux/atom.xml</id>
    <entry xml:lang="en">
        <title>follow-symlinks: tracing the whole link chain</title>
        <published>2026-08-10T00:00:00+00:00</published>
        <updated>2026-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/code/follow-symlinks-tracing-the-link-chain/"/>
        <id>https://colas.nahaboo.net/code/follow-symlinks-tracing-the-link-chain/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/code/follow-symlinks-tracing-the-link-chain/">&lt;p&gt;I just added &lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/colas-bash-lib/blob/master/bin/follow-symlinks&quot;&gt;follow-symlinks&lt;/a&gt;&lt;/strong&gt; to my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/colas-bash-lib&quot;&gt;colas-bash-lib&lt;/a&gt; collection. It is a small bash script that traces and expands all the symlinks of a file, recursively, and shows you the mount points and the dangling links found along the way.&lt;/p&gt;
&lt;p&gt;I made it because there are no existing linux utilities that show both the mount points and the symbolic link traversed to get to the file.&lt;/p&gt;
&lt;h2 id=&quot;what-it-shows&quot;&gt;What it shows&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-shows&quot; aria-label=&quot;Anchor link for: what-it-shows&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Give it the path of a file or directory and it walks the chain, printing each hop:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## /tmp/symtest/chain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Mount: /tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;#39;/tmp/symtest/chain&amp;#39; -&amp;gt; &amp;#39;link-to-real&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  =&amp;gt; /tmp/symtest/link-to-real&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output is made for human consumption:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt; the file is a symbolic link to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;=&amp;gt;&lt;/code&gt; the final target&lt;/li&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt; the path after normalization (resolving &lt;code&gt;/..&lt;/code&gt;, &lt;code&gt;/./&lt;/code&gt;, &lt;code&gt;//&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mount:&lt;/code&gt; a filesystem boundary — printed when the mount point changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*** File not found:&lt;/code&gt; a dangling link&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also resolves the relative links and the &lt;code&gt;..&lt;/code&gt; segments for you, so what you read is what the kernel will actually open, not the spelling on disk.&lt;/p&gt;
&lt;h2 id=&quot;the-dangling-links&quot;&gt;The dangling links&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-dangling-links&quot; aria-label=&quot;Anchor link for: the-dangling-links&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dangling (or broken) links get a useful diagnostic to know the missing link.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## /tmp/symtest/dangling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Mount: /tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;#39;/tmp/symtest/dangling&amp;#39; -&amp;gt; &amp;#39;missing-file&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  *** File not found: /tmp/symtest/missing-file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Because in missing directory: /tmp/symtest/missing-file&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;the-mount-points&quot;&gt;The mount points&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-mount-points&quot; aria-label=&quot;Anchor link for: the-mount-points&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Links that cross a mount point are easy to miss — the file is the same name, but it lives on another filesystem, with its own space and speed characteristics:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## /tmp/symtest/link-to-etc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Mount: /tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;#39;/tmp/symtest/link-to-etc&amp;#39; -&amp;gt; &amp;#39;/etc&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Mount: /&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  =&amp;gt; /etc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;why-i-like-it&quot;&gt;Why I like it&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-i-like-it&quot; aria-label=&quot;Anchor link for: why-i-like-it&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One shot, whole chain&lt;/strong&gt;: it prints everything in one pass instead of me chaining &lt;code&gt;ls -l&lt;/code&gt; and &lt;code&gt;readlink&lt;/code&gt; by hand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A reason, not a symptom&lt;/strong&gt;: for broken links it tells me the missing directory, not just &quot;file not found&quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pure bash, no dependencies&lt;/strong&gt; — it only uses &lt;code&gt;readlink&lt;/code&gt;, &lt;code&gt;stat&lt;/code&gt; and &lt;code&gt;realpath&lt;/code&gt;, all of which are everywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See it and the rest of my bash scripts at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/colas-bash-lib&quot;&gt;colas-bash-lib&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>browser-freezer: freeze the browser when the screen blanks</title>
        <published>2026-08-09T00:00:00+00:00</published>
        <updated>2026-08-09T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/code/browser-freezer/"/>
        <id>https://colas.nahaboo.net/code/browser-freezer/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/code/browser-freezer/">&lt;img src=&#39;browser-freezer.jpg&#39;&gt;
&lt;p&gt;I have a small NUC-style mini PC that runs linux with X11, and I cannot suspend it — probably some hardware incompatibility or BIOS bug, as is often the case on these mini-PCs. So, to minimize power consumption and heat generation, I made &lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/browser-freezer&quot;&gt;browser-freezer&lt;/a&gt;&lt;/strong&gt;: a small and light utility to freeze the browsers when the screen blanks, and un-freeze them on wakeup. On such a machine, the browser is the only thing consuming power when not being used.&lt;/p&gt;
&lt;h2 id=&quot;why-two-parts-c-bash&quot;&gt;Why two parts? C + bash&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-two-parts-c-bash&quot; aria-label=&quot;Anchor link for: why-two-parts-c-bash&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is composed of two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a tiny C daemon &lt;strong&gt;browser-freezer&lt;/strong&gt; that polls the state of the monitor (On / Off) with as less CPU usage as possible (no forks under X11)&lt;/li&gt;
&lt;li&gt;on monitor status change detection, it runs the bash script &lt;strong&gt;browser-freezer-signal&lt;/strong&gt; that sends the SIGSTOP or SIGCONT signal to all browser processes (firefox by default). It uses a bash script for the most possible flexibility and customization, as performance is not an issue there.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wayland&quot;&gt;Wayland&lt;a class=&quot;zola-anchor&quot; href=&quot;#wayland&quot; aria-label=&quot;Anchor link for: wayland&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The initial release was X11 only, but two weeks later I added a Wayland variant: a second binary &lt;code&gt;browser-freezer-wayland&lt;/code&gt; and a wrapper that picks the right one at login depending on &lt;code&gt;$WAYLAND_DISPLAY&lt;/code&gt;. As always with Wayland, it is a second incompatible API to implement, but it works.&lt;/p&gt;
&lt;p&gt;My browsers are the only things consuming power on that machine when idle, so freezing them is the next best thing to suspending the whole PC. Indeed :-)&lt;/p&gt;
&lt;h2 id=&quot;installation-usage-and-more-info&quot;&gt;Installation, Usage, and more info&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation-usage-and-more-info&quot; aria-label=&quot;Anchor link for: installation-usage-and-more-info&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;See the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/browser-freezer&quot;&gt;browser-freezer repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some code and images generated by AI (Gemini), as my C was a bit rusty.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>x-workspace-switcher: a menu to switch and rename X11 workspaces</title>
        <published>2026-08-04T00:00:00+00:00</published>
        <updated>2026-08-04T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/code/x-workspace-switcher/"/>
        <id>https://colas.nahaboo.net/code/x-workspace-switcher/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/code/x-workspace-switcher/">&lt;img src=&#39;x-workspace-switcher.png&#39; align=right width=300&gt;
&lt;p&gt;I switch workspaces dozens of times a day — browser here, terminal there, editor somewhere else — and I could not find a workspace switcher that was convenient. Either they were tiny unreadable icons in a panel, or huge fancy views. I just wanted a readable list of names, plus an easy way to rename the workspace via the programs that run in them.&lt;/p&gt;
&lt;p&gt;So I added &lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/colas-bash-lib&quot;&gt;x-workspace-switcher&lt;/a&gt;&lt;/strong&gt; to my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/colas-bash-lib&quot;&gt;colas-bash-lib&lt;/a&gt;, a single bash script in &lt;code&gt;bin/&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;switching&quot;&gt;Switching&lt;a class=&quot;zola-anchor&quot; href=&quot;#switching&quot; aria-label=&quot;Anchor link for: switching&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run it with no argument and a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/davatorium/rofi&quot;&gt;rofi&lt;/a&gt; menu pops up, listing each workspace with the classes of the windows currently on it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1  ws_1 | firefox, discord&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2  ws_2 | kitty, vim&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I can see at a glance where everything is, instead of remembering. The current workspace is pre-selected. Move with the arrows or incremental search, hit Enter — or just hit the function key of the workspace you want: F6 goes straight to workspace 6.&lt;/p&gt;
&lt;p&gt;Note: I use &lt;code&gt;F6&lt;/code&gt; to go to workspace 6 instead of just &lt;code&gt;6&lt;/code&gt; to not mess with typing 6 during an incremental search. Also I use &lt;code&gt;Super-F6&lt;/code&gt; as a keyboard shortcut to go to Workspace 6, and using functions keys allow for 12 workspaces (or 14 on my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://nzxt.com/en-intl/collections/gaming-keyboards&quot;&gt;NZXT keyboard&lt;/a&gt; :-)&lt;/p&gt;
&lt;h2 id=&quot;renaming&quot;&gt;Renaming&lt;a class=&quot;zola-anchor&quot; href=&quot;#renaming&quot; aria-label=&quot;Anchor link for: renaming&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;x-workspace-switcher new-name&lt;/code&gt; renames the current workspace.&lt;/p&gt;
&lt;p&gt;That turned out to be the interesting part: there is no standard way to rename a workspace on X11. For instance, I have a script that I run in a git repository that sets up my development environment  for it (emacs, kittyies, opencode, ...) and now also name the workspace with the repository name.&lt;/p&gt;
&lt;h2 id=&quot;why-renaming-needs-per-wm-code&quot;&gt;Why renaming needs per-WM code&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-renaming-needs-per-wm-code&quot; aria-label=&quot;Anchor link for: why-renaming-needs-per-wm-code&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each window manager does it its own way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xfce: &lt;code&gt;xfconf-query&lt;/code&gt; on &lt;code&gt;/general/workspace_names&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;i3: &lt;code&gt;i3-msg &quot;rename workspace to ...&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;bspwm: &lt;code&gt;bspc desktop -n&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;GNOME: &lt;code&gt;gsettings&lt;/code&gt; on &lt;code&gt;workspace-names&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;KDE: &lt;code&gt;kwriteconfig&lt;/code&gt; plus a &lt;code&gt;qdbus&lt;/code&gt; reconfigure&lt;/li&gt;
&lt;li&gt;anything else: a python-xlib fallback that rewrites the &lt;code&gt;_NET_DESKTOP_NAMES&lt;/code&gt; property directly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Detection is via &lt;code&gt;wmctrl -m&lt;/code&gt;, helped by &lt;code&gt;XDG_CURRENT_DESKTOP&lt;/code&gt; when the WM name is ambiguous.&lt;/p&gt;
&lt;h2 id=&quot;the-wayland-question&quot;&gt;The Wayland question&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-wayland-question&quot; aria-label=&quot;Anchor link for: the-wayland-question&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As always with Wayland: alas, no. The core protocol has no workspace support, and each compositor invents its own incompatible API. My switcher is X11 only — save your sanity, use X11. :-)&lt;/p&gt;
&lt;h2 id=&quot;installation-usage-and-more-info&quot;&gt;Installation, Usage, and more info&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation-usage-and-more-info&quot; aria-label=&quot;Anchor link for: installation-usage-and-more-info&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;See the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/colas-bash-lib&quot;&gt;colas-bash-lib repository&lt;/a&gt;, the script is &lt;code&gt;bin/x-workspace-switcher&lt;/code&gt;. It needs &lt;code&gt;rofi&lt;/code&gt;; renaming on some WMs needs extra packages (&lt;code&gt;i3-wm bspwm plasma-workspace python3-xlib&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Just copy the script in your PATH (&lt;code&gt;/usr/local/bin&lt;/code&gt;, &lt;code&gt;~/.local/bin/&lt;/code&gt;, ...), and bind it to a keyboard shortcut for convenience. For instance I bound it to Super-W (aka Windows-W) since I bound all my window and workspace management function to Super shortcuts.&lt;/p&gt;
&lt;h2 id=&quot;license&quot;&gt;License&lt;a class=&quot;zola-anchor&quot; href=&quot;#license&quot; aria-label=&quot;Anchor link for: license&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;© Colas Nahaboo, 2026. MIT License. Do what you want with it.
&lt;img src=&quot;https://img.shields.io/badge/Co--Designed%20with-AI-blueviolet?style=flat-square&amp;amp;logo=openai&quot; alt=&quot;Co-Designed with AI&quot; /&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Suntimes, a small shell utility</title>
        <published>2022-03-03T00:00:00+00:00</published>
        <updated>2022-03-03T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/code/suntimes-a-small-shell-utility/"/>
        <id>https://colas.nahaboo.net/code/suntimes-a-small-shell-utility/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/code/suntimes-a-small-shell-utility/">&lt;p&gt;I just made a small command-line utility to display the sunrise and sunset times at a location. It can be quite useful in shell scripts.&lt;/p&gt;
&lt;p&gt;It is a minimal Go wrapper around the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nathan-osman/go-sunrise&quot;&gt;nathan-osman/go-sunrise library&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can find it at my repository: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/suntimes&quot;&gt;GitHub - ColasNahaboo/suntimes&lt;/a&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Bash lessons learned with AoC 2021</title>
        <published>2022-01-11T00:00:00+00:00</published>
        <updated>2022-01-11T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/code/bash-lessons-learned-with-aoc-2021/"/>
        <id>https://colas.nahaboo.net/code/bash-lessons-learned-with-aoc-2021/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/code/bash-lessons-learned-with-aoc-2021/">&lt;p&gt;I completed all the exercises of the Advent of Code 2021 in bash! (see &lt;a href=&quot;/code/advent-of-code-2021&quot;&gt;my previous post&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;You can find my solutions with comments in my GitHub repository at https://github.com/ColasNahaboo/advent-of-code-my-solutions/tree/main/bash/2021&lt;/p&gt;
&lt;p&gt;I must say I &quot;cheated&quot; a bit. My  solution for the Day 24 was too slow in bash, and as I was a bit out of  steam, I did not try to find a smart algorithm. I just noticed that I  solved it by building a bash arithmetic expression (of 1 million  characters...) that I then evaluated in bash, and since its syntax was  exactly the one for C... I just made the bash script compile the bash  expression in C and execute it, using the C compiler as a bash  arithmetic just-in-time compiler :-)&lt;/p&gt;
&lt;p&gt;I just discovered AoC this year, and I am impressed. Challenging, fun,  and a great way to progress. I am going to do the previous years, too,  but in &quot;real&quot; languages this time. At least ones with data structures... I will start with Go.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot;&gt;What I learned:&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-i-learned&quot; aria-label=&quot;Anchor link for: what-i-learned&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Coding in bash is not so bad, even if it can border on insanity at times :-).&lt;/li&gt;
&lt;li&gt;Modern bash features are often overlooked but very useful.&lt;/li&gt;
&lt;li&gt;Passing shellcheck should be a mandatory goal for each bash programmer. I resented it at first since I thought it was adding unecessary syntaxic sugar to my code until I realized that it was a symptom that my coding style was the problem.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;[[...]]&lt;/code&gt; for strings and &lt;code&gt;((...))&lt;/code&gt; for integers other any of the legacy constructs like &lt;code&gt;[...]&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, etc... The code is then much cleaner and safer (and a tad faster), as you do not have to quote as much. E.g: &lt;code&gt;[[ -z foo ]]&lt;/code&gt; instead of &lt;code&gt;[ -z &quot;$foo&quot; ]&lt;/code&gt;, or even &lt;code&gt;((i=j))&lt;/code&gt; instead of &lt;code&gt;i=&quot;$j&quot;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;but&lt;/strong&gt;, this makes traditional debugging with &lt;code&gt;set -x&lt;/code&gt; less useful as the values of variables are not displayed anymore. E.g if j is 2, the tracing of &lt;code&gt;i=&quot;$j&quot;&lt;/code&gt; shows &lt;code&gt;i=2&lt;/code&gt; whereas the tracing of &lt;code&gt;((i=j))&lt;/code&gt; only shows &lt;code&gt;((i=j))&lt;/code&gt;. This could be where a bash debugger would be useful, but I know only one, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://bashdb.sourceforge.net/bashdb.html&quot;&gt;bashdb&lt;/a&gt;, and it does not seem updated anymore, and I could not find a version working with bash 5.1. The &lt;code&gt;trap DEBUG&lt;/code&gt; trick can be useful, though.&lt;/li&gt;
&lt;li&gt;So, I tend to write now &lt;code&gt;i=$((j+k))&lt;/code&gt; while developing code, and maybe later for production switch to the a bit more efficient &lt;code&gt;((i = j+k))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I avoided arrays in bash because I found out they were abysmally slow when first introduced, to the point that managing data in files with grep, sed, ... was actually faster than using arrays. But not anymore! Bash arrays should now be used as much as possible.&lt;/li&gt;
&lt;li&gt;A lot of bash functions can &quot;map&quot; on arrays. For instance &lt;code&gt;${tab[@]//x/y}&lt;/code&gt; will string-replace x by y in all the elements of the array tab, and is super fast.&lt;/li&gt;
&lt;li&gt;Use arrays rather than the classic way to represent lists in bash by space-separated (or tab-separated) substrings in a  string.&lt;/li&gt;
&lt;li&gt;Bash can have typed variables: integer ones via &lt;code&gt;declare -i&lt;/code&gt; or &lt;code&gt;local -i&lt;/code&gt;, and using them makes your code safer.&lt;/li&gt;
&lt;li&gt;Bash functions can be passed variables by name, useful for efficiency to avoid copying big arrays or strings, and to provide multiple return values by modifying passed variables. But it cannot recurse as it is not a passing by reference, but by name.&lt;/li&gt;
&lt;li&gt;Working with arrays makes using &lt;code&gt;$(...)&lt;/code&gt; impractical, as commands are executed in a subshell and cannot access arrays anymore to update them in the parent shell. So I tend to pass the return value(s) into global variables of the same name of a function. E.g. instead of &lt;code&gt;x=$(foo)&lt;/code&gt;, I write &lt;code&gt;foo; x=&quot;$foo&quot;&lt;/code&gt;. Or pass variables by name to set them if I want to return multiple results.&lt;/li&gt;
&lt;li&gt;To parse a space-separated string, the fastest is using &lt;code&gt;set&lt;/code&gt; to map the elements in the positional parameters &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, ... then the &lt;code&gt;${string#* }&lt;/code&gt; and &lt;code&gt;${string% *}&lt;/code&gt; operators are the fastest, closely followed by a read, the full &lt;code&gt;[[ $string =~ ([-[:digit:]]+)[[:space:]]... ]]&lt;/code&gt; being 3 times slower. And if possible, using indexes is even faster: &lt;code&gt;${string:i:j}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the faster &lt;code&gt;$(&amp;lt; filename)&lt;/code&gt; instead of &lt;code&gt;$(cat filename)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To copy an associative array A1 to A2 in bash 4.4+, do:
&lt;code&gt;A1_def=$(declare -p A1) &amp;amp;&amp;amp; declare -A A2=&quot;${A1_def#*=}&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To access more than 9 parameters in a function: use braces: &lt;code&gt;$10&lt;/code&gt; wont work, but &lt;code&gt;${10}&lt;/code&gt; does.&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Advent of Code 2021</title>
        <published>2021-12-07T00:00:00+00:00</published>
        <updated>2021-12-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/code/advent-of-code-2021/"/>
        <id>https://colas.nahaboo.net/code/advent-of-code-2021/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/code/advent-of-code-2021/">&lt;p&gt;I just discovered the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://adventofcode.com/&quot;&gt;Advent of code&lt;/a&gt; coding challenge. It exists since 2015, and seems really interesting in that it is language-agnostic.&lt;/p&gt;
&lt;p&gt;Each day a problem is described, with input files consisting of numeric values for the problem. You must submit the answer which is a number by whatever means you want.&lt;/p&gt;
&lt;p&gt;I started to do the current 2021 challenge, in &lt;strong&gt;bash&lt;/strong&gt; to force myself to code in a more modern style that pass &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.shellcheck.net/&quot;&gt;shellcheck&lt;/a&gt;. And later, i will probably do the other years in &lt;strong&gt;Go&lt;/strong&gt; to learn it.&lt;/p&gt;
&lt;p&gt;I publish my solutions as I code them on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ColasNahaboo/advent-of-code-my-solutions/tree/main/bash/2021&quot;&gt;my github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://adventofcode.com/&quot;&gt;advent of code&lt;/a&gt; (aka AOC) site&lt;/li&gt;
&lt;li&gt;The sub-reddit  &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.reddit.com/r/adventofcode/&quot;&gt;/r/adventofcode&lt;/a&gt; to discuss AOC&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Mercurial web templating</title>
        <published>2008-10-09T00:00:00+00:00</published>
        <updated>2008-10-09T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://colas.nahaboo.net/blog/mercurial-web-templating/"/>
        <id>https://colas.nahaboo.net/blog/mercurial-web-templating/</id>
        
        <content type="html" xml:base="https://colas.nahaboo.net/blog/mercurial-web-templating/">&lt;p&gt;For some time now, I have seen the light and I switched to the new wave
of the Distributed Source Control management systems. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=4XpnKHJAok8&quot;&gt;Linus famous
video&lt;/a&gt; of his Google talk
decided me to try. I was a bit apprehensive at first, wary of engaging
myself on a technology that would bring more problems than solutions,
but after some days of use, the realisation dawned over me: Distributed
Source Control may be one little step for a programmer, but it is a
giant step for programming. Why? because, its &lt;strong&gt;mental model actually
follows your first intuitions&lt;/strong&gt; that most of us developed as young
programmers before using any source control system. Suppose you want to
try a feature? instead of just copying the directory, you clone it. You
mess an operation? you just remove the directory, no embarrassing traces
left to keep the burning scar of shame on you for the following decades
of a central repository. You are used to think of your enhancements as
patches, you can work with patches. I could go on and on, but many
people have done it much better than me so I&#39;ll just say that you should
definitely try it.&lt;/p&gt;
&lt;p&gt;By the way, between the 3 main contenders, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/&quot;&gt;git&lt;/a&gt;,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.mercurial-scm.org/&quot;&gt;mercurial&lt;/a&gt; (aka HG), and
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/GNU_Bazaar&quot;&gt;bazaar&lt;/a&gt;, I chose mercurial because of its
simplicity, its better support of windows (I work in Linux since 1995
but my coworkers currently use Windows), and because some people at ILOG
started using git so I wanted to be able to try something else. I did
not choose bazaar as I wanted to stay close enough of git, to be able to
switch to it if ever my dream to work in a windows-free world
materializes one day...&lt;/p&gt;
&lt;p&gt;So I started to set up a public web repository of my Open Source personal
work with mercurial, which gave me a simple way to publish my work in
full detail, but, although mercurial is quite easy to use, but I had a
bit of trouble figuring out how to customize its look &amp;amp; feel.&lt;/p&gt;
</content>
        
    </entry>
</feed>
