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:
- Define flags using methods like
flag.String()
,flag.Bool()
,flag.Int()
, etc. - Bind an existing variable to the command-line flag using
flag.StringVar()
,flag.IntVar()
, etc. - Create custom flag by declaring a type that implements the
flag.Value
interface and then usingflag.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