Golang Command Line Flags Options

Command-line programs often accept flags or options from users to customize the command’s execution. Flags are key-value pairs that are added after the command name while running the command.

Go lets you accept command line flags using the flags package from the standard library. In this article, you’ll learn how to accept flags for your command-line program.

Go Command Line Flags

To accept command line flags, you need to define flags to capture values from the command line. You can do it in multiple ways:

  1. Define flags using methods like flag.String(), flag.Bool(), flag.Int(), etc.
  2. Bind an existing variable to the command-line flag using flag.StringVar(), flag.IntVar(), etc.
  3. Create custom flag by declaring a type that implements the flag.Value interface and then using flag.Var() method to bind a variable of the custom type with the command-line flag.

Let’s look at the first two approaches in the following example. We’ll see another example that demonstrates the 3rd approach.

package main

import (
	"flag"
	"fmt"
	"strings"
)

func main() {
	// Declare a string flag called name with a default value ("Guest") and a help message
	name := flag.String("name", "Guest", "specify your name")

	// Declare a flag called age with default value of 0 and a help message
	age := flag.Int("age", 0, "specify your age")

	// Bind the command-line flag with an existing variable
	var country string
	flag.StringVar(&country, "country", "", "enter your country")

    // Enable command-line parsing
	flag.Parse()

	fmt.Printf("Hello %s\n", *name)
	fmt.Printf("Your age is %d\n", *age)
	fmt.Printf("Your are from %s\n", country)
}
# Build the program
$ go build command-line-flags.go

Use -h or —help flags to get the help-text of the command-line program.

$ ./command-line-flags -h
Usage of ./command-line-flags:
  -age int
    	specify your age
  -country string
    	enter your country
  -name string
    	specify your name (default "Guest")

Supply flags using space delimited key-value pairs

$ ./command-line-flags -name Rajeev -age 28 -country India
Hello Rajeev
Your age is 28
Your are from India

Supply flags with key=value format

$ ./command-line-flags -name=Rajeev -age=28 -country="United Kingdom"
Hello Rajeev
Your age is 28
Your are from United Kingdom

Flags fallback to the default values if not specified

$ ./command-line-flags -age=24 -country="United States"
Hello Guest
Your age is 24
Your are from United States

Creating a custom command-line flag

The following example demonstrates how you can create a custom flag. In this example, we define and parse a comma-separated command-line flag.

package main

import (
	"flag"
	"fmt"
	"strings"
)

// A custom type that implements the flag.Value interface
type hobbies []string

func (h *hobbies) String() string {
	return fmt.Sprint(*h)
}

func (h *hobbies) Set(value string) error {
	for _, hobby := range strings.Split(value, ",") {
		*h = append(*h, hobby)
	}
	return nil
}

func main() {
    // Define a custom flag
	var hobbiesFlag hobbies
	flag.Var(&hobbiesFlag, "hobbies", "comma separated list of hobbies")

    // Enable command-line parsing
	flag.Parse()

	fmt.Printf("Your hobbies are: ")
	for _, hobby := range hobbiesFlag {
		fmt.Printf("%s ", hobby)
	}
	fmt.Println()
}
# Output
$ ./command-line-flags -hobbies=Sports,Photography,Coding
Your hobbies are: Sports Photography Coding

Working with Positional Arguments using flag package

The flag.Parse() function continues to parse flags that it encounters until it detects a non-flag argument (positional argument). The flag package makes the positional arguments available through the Args() and Arg() functions.

Note that the flag package requires all flags to appear before positional arguments. Otherwise, the flags will be interpreted as positional arguments.

Let’s look at an example of positional arguments. Let’s say we’re writing a program that searches for a list of keywords from a start line number to a destination line number in a file. In the following example, we accept the start and end line numbers as flags and the list of keywords as positional arguments:

package main

import (
	"flag"
	"fmt"
)

func main() {
	s := flag.Int("s", 0, "start line number")
    t := flag.Int("t", 0, "end line number")

	// Enable command-line parsing
	flag.Parse()

	fmt.Printf("Search file from line number %d to %d\n", *s, *t)

    // Read all the positional arguments
	fmt.Println("for keywords:", flag.Args())

    // Read the i'th positional argument
	i := 0
	fmt.Printf("The keyword at index %d: %v\n", i, flag.Arg(i))
}

Here is how you supply flag and non-flag arguments to the program:

$ go build command-line-flags.go

$ ./command-line-flags -s 1 -t 100 Go Java
Search file from line number 1 to 100
for keywords: [Go Java]
The keyword at index 0: Go

You must specify flags before positional arguments. Otherwise, the flags will also be interpreted as positional arguments:

$ ./command-line-flags Go Java -s 1 -t 100
Search file from line number 0 to 0
for keywords: [Go Java -s 1 -t 100]
The keyword at index 0: Go