Handle Argument Flags in Go

I recently started building up a lot of small little go packages that will lead up to a more comprehensive automated video editing tool I want to build.

While creating these small packages, I wanted to create a simple CLI program to interact with each and do it more properly than I had with the shell scripts.

I wanted to start by handling arguments in a more proper way, namely, parsing flags passed to the program.

Turns out, go already has a pretty nice package in the standard library for this called flag.

Setup Valid Flags

So, how do we go about declaring what flags we want to accept? Well, there are two main approaches you can use.

myStrFlag := flag.String("mystr", "", "This is my string flag")

This approach declares a flag called "mystr" and when your arguments are parsed, will return a pointer to the value the function returned. The second argument is the default value if no value is given for that flag. The final argument is the message displayed when the usage info for the flags is shown. (more on that later)

There is a similar way to achieve this:

var myStrFlag string
flag.StringVar(&myStrFlag, "mystr", "", "This is my string")

This is almost identical to the first way, except instead of the function returning a pointer, we give it a pointer to an existing variable and the value is stored in that variable using the pointer. I prefer this approach myself.

Flag Argument Formats

Using the previous example, if we declare a valid flag called "mystr", the flag can be passed in several formats that are valid.

  • -mystr=value
  • --mystr=value
  • -mystr value
  • --mystr value

If the flag is a boolean flag, these are the valid formats:

  • -mybool
  • --mybool
  • -mybool=value
  • --mybool=value

You'll notice with boolean flags we can't do the -flag value syntax. I already lost about an hour one day not realizing this when the rest of the flags weren't being parsed. Turns out I was accidentally trying to use a boolean flag like any other flag and passing the value with a space, which causes the flag parsing to stop.

Flag Usage

One of the great advantages of the flag package is it makes it super easy to print the usage info of your flags!

By default, if you want to display the usage information, all you have to do is do:

flag.PrintDefaults()

This will print out each flag you've defined, along with that help message you pass in as the last argument to each flag definition.

Now, if you want to change what gets printed when printing the usage, you can override it easily.

flag.Usage = func() {
  fmt.Println("This is my new help message")
  fmt.Println("This will get displayed instead of the default messages")
}

Parsing Arguments

So we've declared what our flags are and set up our usage message, how do we actually parse the program arguments into our variables? Thankfully, with one function call:

flag.Parse()

That is it, that is all you had to do and tada, you got values stored in your variables!

Now, you noticed the flags are actually typed as well (StringVar, Intvar, etc), while parsing the arguments, if someone gave a file path for an integer variable, the program will automatically display an error message, print the default usage, and exit! That is a lot of functionality right out of the box for basically free.

Summary

You should now be able to:

  • Define a set of valid flag arguments for your program
  • Have default values and usage information for said flags
  • Parse the program arguments into your variables
  • Print the usage information if needed

If you have any further questions about what you can do with the flag package, just check the docs.

Thank you for your time!


Did you find this information useful? If so, consider heading over to my donation page and drop me some support.

Want to ask a question or just chat? Contact me here