Go is a great programming language for building command line tools.
The most popular command line package in the ecosystem being spf13’s Cobra.
The standard library is also a great option when you combine the os
and flag
packages.
You may be asking yourself, which one is right for me?
The package you choose should be based on the functionality you’re looking for.
If you’re just building a simple interface for application start up, you may not need something as robust as cobra.
You could probably get away with just using the standard library if all you need is some rudimentary flag parsing.
Now what if you’re in the middle?
What if you know you don’t need half the things cobra offers but you also need something more structured than a single switch statement for evaluating all your operating system arguments?
cdr/cli is a minimalistic go package for building command line tools.
It’s simple, easy to use, and allows you to quickly put a CLI together.
Let's get a little more familiar with this package by building a port scanner in go.
Let's start by initializing our mod
file and an idiomatic go application structure.
Another common pattern is to keep each command in its own dir under cmd
, including that command's subcommands.
You can find an example of that approach in the go standard library.
Our root command will only have one subcommand for our demo so I feel that justifies keeping them in the same directory for the purpose of this demo.
The port-scanner/cmd/port-scanner
dir is our entry point.
We can define our root command here.
port-scanner/cmd/port-scanner/root.go
Great! Now that we’ve defined our root command, we can run it out of our main func.
port-scanner/cmd/port-scanner/main.go
Cool, let's compile and run our program and see what we have so far.
A great start no doubt, but we’ll need to add some subcommands if we want our port scanner to do anything.
I would normally implement the port scanner under the internal
package or the pkg
package (depending on whether or not I wanted to publish this as a public package for others to use), but to keep this short and sweet, let's implement the subcommand and the port scanner in the same file.
port-scanner/cmd/port-scanner/scan.go
Great, now let's re-compile our program and run the root command to see what the output looks like.
So far so good.
Let’s see what the help output for the scan subcommand looks like.
Beautiful. I think we’re ready to test this thing out.
Let's start by opening a new shell and firing up a local python web server.
Let’s run our port scanner in a different shell, and while we’re at it let's use the subcommand alias we defined for our scan command.
We’ll also want to use our --all
flag since our python server is running on port 8000 (which is outside our default port-range).
There is a discrepancy in the output because I’ve intentionally omitted certain ports for security reasons.
I hope you enjoyed this tutorial.
You can find this code on my github.
I encourage you to see what modifications you can make on your own.
More specifically, why don’t you try adding the capability to scan multiple hosts or an entire network.
That’s how simple it is to build command line tools in go using the cdr/cli package.
Hope you found this useful.
Much love,
—Faris
Want to stay up to date on all things Coder? Subscribe to our monthly newsletter and be the first to know when we release new things!