Being able to write your own command-line tools is a great skill to have: automate all the things!
Unfortunately, writing CLI tools is still most often done with Bash. My strong opinion - weakly held - is that there are only two good kinds of Bash scripts:
the ones that are five lines long or less
the ones that are written and maintained by others
Fortunately, retiring Bash is pretty simple: you just have to use your favorite programming language instead!
I've played around with Kotlin Multiplatform and not only built a cool CLI tool with it, but I've packaged it as a template project that you can leverage to get started faster!
git-standup is a smart little tool for people like me who often panic before the stand-up. What the hell did I do yesterday? That command refreshes my mind by browsing all git repositories and printing the commits that I made yesterday. Try it out, it may well become part of your workflow.
Clone the repo:
git clone https://github.com/jmfayard/kotlin-cli-starter
cd kotlin-cli-starter
./gradlew install
git standup
./gradlew install will install the tool as a native executable.
There are two more options available:
./gradlew run will run it on the JVM
./gradlew jsNodeRun will run it on Node.js
Same common code, multiple platforms.
Modern Programming Practices
A traditional Bash script contains
a syntax where you can't remember how to do an if/else of a for loop
unreadable code due to Code golf : ztf -P -c -D -a
no dependency management (apart from an error message: ztf not found)
one file that does everything
no build system
no IDE support (vim should be enough for everybody)
no unit tests
no CI/CD
By choosing a modern programming language like Kotlin instead, we get to have
a modern syntax
readable code
separation of concerns in multiple functions, files, class and packages
unit tests. Here, they are run on all platforms with ./gradlew allRun
CI-CD. Here, the unit tests are run on GitHub Actions. See workflow
That may sound obvious, yet people still write their CLI tools in Bash, so it's worth repeating.
Why support multiple platforms?
The three platforms have different characteristics, and by making your code available on all platforms, you can decide which one works better for you:
The JVM has a plethora of available libraries, superb tooling support ; it lacks a package manager and is slow to start
A native stand-alone executable starts very fast, it can be distributed by Homebrew for example - I make a Homebrew recipe
There are also a plethora of libraries on Node.js, and packaging it is easy with npm-publish. My version of git-standup is available at https://www.npmjs.com/package/kotlin-cli-starter and I find it fascinating that I could do so without writing a line of JavaScript.
But mostly it's a good opportunity to learn Kotlin/Multiplatform, a fascinating technology, but one that can also be complex. By writing a CLI tool with Kotlin/Multiplatform, you start with something simple.
What is it like to write Kotlin Multiplatform code?
It feels like regular Kotlin once you have the abstractions you need in place, and all you need is to modify commonMain.
I especially liked CliKt for arguments parsing. It has this killer feature that it can generate automatically not only the help message, but also shell completions for Bash, Zsh, and Fish.
The drawback: it takes time to set everything up
Building this project was a lot of fun, and I learned a lot, but it also took lots of time.
Setting up Gradle and a hierarchy of srcsets - not trivial at all
What should I do next time if I don't have so much time available?
Go back to Bash?
kotlin-cli-starter : starter project to build CLI tools
I really didn't want to go back to Bash.
This is when I decided to go another route, and transform my experiment in a starter project that I, and everyone, could re-use.
Click Use this template and you get a head start for writing your own CLI tool.
I have put comments starting with CUSTOMIZE_ME in all places you need to customize
Find them with Edit > File > Find in Files
Conclusion
Automate your workflow by using command-line tools. But think twice before using Bash like in the previous century. Kotlin and other modern programming language could well be a far superior solution.
Using Kotlin Multiplatform gives you the strength of each platform, like a wealth of libraries for the JVM, a fast startup for native executables and a package manager (npm) for Node.js.
It is not strictly necessary, but if you want to learn Kotlin Multiplatform, this is a great point to start.
It could take a while to set up from scratch, though.
This is why I transformed my project to a starter project / GitHub template that you can reuse.