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.