About
As I continued to learn more about Go, I found myself yearning for the ability to write useful, idiomatic Go applications. Once I started to use the flag module from Go's standard library it dawned on me that I could write useful console-based Go programs, which was exactly what I needed as a Go developer looking for my next project. This post will share what I've learnt and how you can also build command-line applications in Go.
Flags
Context
The flag module provides a library that is capable of parsing command-line options. A common pattern is to define each command-line option as a package-local variable, with one package-local variable per flag.
The flag module can be especially nice when it is combined with a
package-level init
function that is run when a package is
initialized. This is the perfect place to define and parse our flags.
Let's materialize our idea into something concrete, with the
package-level help
and username
variables being
used to store our flag values:
package main
import (
"flag"
)
var help bool
var username string
func init() {
flag.BoolVar(&help, "h", false, "Show help")
flag.StringVar(&username, "u", "", "Set username")
flag.Parse()
}
Explanation
The flag.BoolVar
and flag.StringVar
function
binds a flag to a package-local variable. The first argument is a pointer
to the variable where we want to store a flag value, the second argument
is the flag, the third argument is a default value, and the fourth
argument describes the flag. Finally, we parse os.Args
with
the call to flag.Parse()
and this sets up our main method to
receive flag variables that have been populated.
Main
Context
The previous example sets us up nicely to implement the
main
function and receive the parsed flag options.
package main
import (
"fmt"
"flag"
"os"
)
var help bool
var username string
func main() {
if help {
fmt.Printf("usage: %s\n", os.Args[0])
} else if len(username) > 0 {
fmt.Printf("Hello, %s!", username)
} else {
fmt.Printf("Hello, anonymous")
}
}
func init() {
flag.BoolVar(&help, "h", false, "Show help")
flag.StringVar(&username, "u", "", "Set username")
flag.Parse()
}
Explanation
The above sample first runs the init
function, and parses
our flags into a set of package-level variables. By the time the
main
function executes, the flag variables have been
initialized. We can then implement logic on top of our flag variables.
That's more or less it, this is a simple and idiomatic pattern for
parsing command line options in Go.
Conclusion
This post was mainly written to help me memorize a common pattern in Go, and it is a pattern I often revisit when building simple command-line applications in Go. It can be adapted to more complex scenarios as well without too much fuss.