Nifty Unixhome-ingo iterations blog home

Posted Monday, 26-Oct-2026 by Ingo Karkat

As one's toolset grows with time, it becomes increasingly difficult to keep things consistent and up-to-date. You learn new tricks, add new development tools, or realize that an old idiom you've used pervasively in the past has a problem. If you don't update all of your projects, things quickly devolve into a mess of inconsistent stuff. It's a real struggle; here are three examples that show how I try to fight back.

26-Sep-2026

I've encountered an old-style Bats test case that didn't yet use the bats-assert test library. I must have missed that (likely because it was in my extensions subtree, not the regular bin one)! Fortunately, because I had encoded most of the conversion into a custom :BatsConvert Vim command, doing the conversion, even after so much time, was a breeze. But… are there any other such missed test cases? I quickly1 devised a shell command that would answer that question:

$ Unixhome-ingo --predicate-command "\
    negateThis --status-99-is-noop \
    eachDir --worst-status --local-dir --command \
    '! hasglobmatch \"*.bats\" || test -e fixture.bash' \
    -- tests/*/"
/home/inkarkat/Unixhome/bin/ingo/shell-user-interactions
/home/inkarkat/Unixhome/bin/ingo/reldate
/home/inkarkat/Unixhome/lib/ingo/scripting-setup

explanation

In the end, the command reported one actual old-style test (reldate) that I had overlooked so far; the other two were false positives (shell-user-interactions has tests that reuse a fixture from an adjacent subdir, and scripting-setup is a demo that intentionally doesn't use the library).

  1. I have to admit that in the process of developing this command, I've struggled a bit with the required negations, and had to extend both the eachDir and negateThis commands a bit to make it work so smoothly that I felt good about bragging about it on my home page.
04-Oct-2026

Two more recent uses of Unixhome-ingo iteration:

  1. Find all projects that have automated tests but no GitHub workflow that runs them:
    $ Unixhome-ingo --with-remote -P '[ -d tests/ -a ! -e .github/workflows/build.yml ]'
  2. Find all projects that have a GitHub workflow but no "Build passing" badge yet:
    $ Unixhome-ingo --with-remote -P '[ -e .github/workflows/build.yml ] && ! grep -q badge.svg README.md'
26-Oct-2026

Another nifty use of Unixhome-ingo iteration: 60+ of my scripts had this cleanup command:

trap '${DEBUG:+debugcommand --} rm -f -- "$filespec" 2>/dev/null' EXIT

This uses my shell-debugging project's debugcommand that allows skipping the cleanup if the DEBUG environment variable contains the right value (so one can inspect the temporary files that would normally be removed when the script ends). For an examplescript, that would be DEBUG=examplescript!; the ! is the extension that causes the skipping:

debugcommand --help
When $DEBUG refers to DEBUGGEE!, COMMAND is NOT executed and just logged as an execution trace.

What I realized today during troubleshooting is that the concurrent use of the debugtrace was in conflict with that, as the use of the ! there skips the execution of the following script:

debugtrace --help
When $DEBUG refers to DEBUGGEE![N], an exit command is printed so that the
caller exits prematurely [with an exit status of N].

Yeah, I've come a long way since I started skipping the cleanup via a simple check if $DEBUG was defined, and manually inserting set -x at the top of scripts to enable tracing…

Okay, back to the problem: To avoid the problem of the overload of the ! extension, I can simply assign a module to the cleanup; i.e. I need to insert a --module cleanup argument behind debugcommand. To find all affected places, I need to find all uses of the original, as-yet unchanged command. This command-line did the trick:

$ Unixhome-ingo --no-header --command 'ackf "debugcommand .* rm" | fackF "debugcommand --module cleanup" | prependCwd' | fv

explanation

In GVIM, I use :argadd to put those files onto the argument list, then go through them one by one to do the edits. An ad-hoc search command quickly brings me to all locations, and the :wn[ext] command to the following file. I could have recorded a macro or written a :substitute command, but that wouldn't have saved much time as I would need to take a closer look at the diffs then. Another benefit of the manual edits is that one may accidentally see other issues or outdated styling that can be corrected on the go (boyscout rule).

Ingo Karkat, 26-Oct-2026

ingo's blog is licensed under Attribution-ShareAlike 4.0 International

blog comments powered by Disqus