HOWTO: Abuse ZSH Parameter Expansion to Expand GNU-Style Arguments (...and, back from Hiatus)

Sunday, October 6, 2024

GNU-Style Command Line Argument Expansion

#!/bin/zsh
setopt extendedglob
typeset -a cli=( ${${${(z)${${(qqq)argv[@]}:-}/#(#m)\"-[^-]?*/${${(@)${(s::)MATCH:1:-1}:#-}//(#m)?/-$MATCH}}##\"}%%\"} )
print -l -- "${cli[@]}"

Save that to test.zsh and run test.zsh -abcd foo --bar and it'll print the contents of the $cli array:

-a
-b
-c
-d
foo
--bar

So, let's just be clear: this is insane and falls into the category of "just because you can doesn't mean you should." This is a "solved problem" that has many options which are easier to understand. This method offers exactly one benefit: the target platform I was working with for this project was mingw under Windows and, like WSL1, it had this very painful performance issue when a shell had to create a sub-shell -- basically, any time you $(run something) and that means "if your function returns anything except for a byte", it's going to have a serious cost to place that into a variable the convenient way. When diagnosing why a build script I wrote would ran almost instantly in a virtual Linux instance but took several seconds in mingw, I discovered the code that parsed the command-line took two seconds to complete. This version, combined with other hacks to eliminate sub-shelling everywhere else yielded a script that ran as fast on Windows as on Linux.

Of course, the reason it's a bad idea to use something like this is being that I wrote it a couple of years ago, I struggle to explain every part of it. The "dumbed down version" (read: mostly inaccurate) is that it first quotes the argument array, converts it to a string and does all of the "splitting of the short arguments" using "a string containing all of the arguments escaped in a manner compatible with later being converted to an array", and after a few replace operations it does just that, leaving you with an explicitly typed array and each.

And Finally, I'm Back

I hope, anyway. Priorities being what they are, this one took the back burner to my children, my family and my job coupled with the untimely demise of the software I wrote to make converting my Markdown notes to blog posts (shortly after I'd completed the software). It was a stupid error; I'd written the code over the weekend using a laptop while visiting my folk's place up north. The best internet we could get at the time was AT&T DSL which was down more than it was up and was very slow. I tended to write up there. But the code that made up the solution was never given a proper place in my git server -- it was rarely accessible up north due to outages. You can imagine where this is headed: the laptop's drive failed: gone. Motivation to write blog posts: gone.

And I was never writing for an audience. I mean, I'm not against such things but "priorities being what they are", I don't have enough desire to dedicate the required time. It was always about 1 having a place to put things that are very useful, but not used often enough so I'll almost certainly forget what bit of code had that answer (like, how do I parse arguments in a script without subshells) and 2 as an outlet. I enjoy writing. Lately, as well, it's becoming about having a place for my children to know a little more about what I do. I'm not sure how I'm going to accomplish that but I love writing software and if that's what they want to do, it'd be nice if they had a place to look to see what it was like "when Dad wrote software." If for no other reason than to give them comfort that "yes, the universe of software development really does radically evolve about every six months and it is enjoyable to keep up with it if you're wired that way. Not always, no. But -- for me anyway -- the vast majority of the time.

Outside of that my job focus went from what was called Microsoft Skype for Business 2016 at the time to a job where I got to put my fingers in code in people's homes through a few IoT projects, doing a lightweight 3D tool in three.js (in React), some fun with federated identity with gulp XML (Azure AD B2C), and lately I've been writing code for the Buzzword "Generative AI." So there are some gaps here that are probably not going to get filled. :)