Select Page

How to Use the Flag Package in Go

Manoj Debnath
Published: July 19, 2022

The flag package in Go is used to develop a UNIX system-like program that accepts command-line arguments to manipulate its behavior in some form. In Golang, flag is a built-in package shipped with Go standard library. A flag is a formatted string that is passed as an argument to a program so that, according to the flag passed, the control or behavior of the program has some augmented utilities. This Go programming tutorial introduces this feature with some code examples.

Read: The Best Tools for Remote Developers

What is the flag Package in Go?

Almost all terminal commands used in Windows or UNIX/Linux systems have some flags associated with them. In Windows, these flags are called switches. and. in UNIX/Linux systems, they are known simply as a flag. The essence, however, is the same – to control program behavior at runtime. Since flag is a very common term in UNIX/Linux, in this tutorial, we will focus on this platform only. Most commands used in UNIX/Linux have more utilities built into them already. They typically serve their normal functionality as we give the command in the terminal. If it serves our purpose, it is fine. But if we want more from the program, we can look at many of its flags and find their extra abilities. These abilities can be utilized by passing arguments in the form of flags while executing the command in the command line. For example, if developers type man cat in the Linux terminal, they can get the following information:

Golang flag Package

This opens the manual for the cat command where we get all the information about the command and also the available flags (which may be optional) and what they do. For example, programmers could use the cat command to open a text file as follows:

$ cat abc.txt

this is sample text. First line.
this is another sample text. Second line.

Now if we use a flag such as -n or – – number this will number all output, as follows:

$ cat -n abc.txt

1 this is sample text. First line.
2 this is another sample text. Second line.

Although the basic utility of the cat command is to concatenate files and print in the standard output, there are some more utilities built into it that can be unleashed using various flags such as:

...
-b, --number-nonblank
              number non empty output lines, overrides -n

-n, --number
              number all output lines
...

The flags above control the behavior of the cat program in this case. This is typical of any UNIX/Linux command.

Now, what if a programmer wants to implement such behavior using a Go program? The flag package provided in the standard library helps in doing that. Note that there are quite a few third-party packages for handling flags through the Go program, but in this tutorial, we are concerned with only the flag package provided by the built-in library.

Use Cases for the flag Package in Go?

Although flags are nothing but formatted strings passed as a command-line argument, dealing with them in a program is actually not very easy or straightforward, especially when we want to support supplying multiple flags as an argument. Apart from focussing on the logic of the program, the programmer, without a flag package, also has to write the logic of the pattern supplied as a flag in the command line and provide appropriate functionality according to it.

Sometimes flags and file names may both be passed in the command line. Logic must be there to identify and separately use them because both of them are actually formatted strings that may be ambiguous. In a nutshell, it takes a lot of time to implement the flag behavior in a program without any external assistance from a package like flag. Therefore, if we need to develop a UNIX system type of utility, the flag package can make a developer’s task much easier. Interestingly, Go is built by people who have a UNIX background, and it is not a surprise that many of its flavors will leave their mark in some form or another. Whatever the reason, it is a nice utility to have in Go.

Go Code Examples for the flag Package Utility

Let’s try a very simple example to show how to use the flag package in Go:

package main

import (
	"flag"
	"fmt"
)


func main() {

	str1 := flag.String("u", "root", "username")
	str2 := flag.String("p", "", "password")
	flag.Parse()
	fmt.Println("Username : ", *str1)
	fmt.Println("Password : ", *str2)
}

Observe that this program recognizes two command-line options: -u for username and -p for password. The flag.String(“u”, “root”, “username”) statement defines a string command-line option; the first one is named u with the default value as root. The third parameter is the usage string displayed with the usage of the program. Therefore, when run the program as follows:

$ go run main.go

It simply runs with the default values given in the flags. If we supply the command line option:

$ go run main.go -u user123 -p secret123

The values supplied to the command line are accepted in the respective variables. Also, note that we can change the order or supply only one option as follows – it still works just fine:

$ go run main.go -p secret123 -u user123
$ go run main.go -p secret123 
$ go run main.go -u user123

Now, what happens when programmers supply the -h flag. Observe that we have not implemented any option named h, but it still works; it simply prints the usage information of the program and the flags:

$ go run main.go -h

This means a lot of things are actually taken care of by the flag package in the background. It is practically impossible to write command-line functionality with so few lines of code without support from the flag package. A C programmer will certainly be able to appreciate the help provided by the flag package in Go. This is actually what the flag package is for in Go.

Read: Top Productivity Tools for Developers

Key Functions in the Go flag Package

The flag package provides a flag.Bool function that defines a Boolean command-line option with name, value, and usage strings just like the flag.String function. Similarly, there are functions for integer, unsigned integer, and var that defines user-defined implementation of type values. The flag package automatically converts the input associated with the respective function flag to its corresponding value – such as converting input associated with flag.Int to an integer value. Also, it makes sure that an integer value is provided, otherwise it flags an error message at runtime.

A variation of this function has a name with the suffix var. There are functions called BoolVar, StringVar, IntVar, etc. These functions work in the same way as their counterpart, only without suffixes. For example, the difference between flag.Bool and flag.BoolVar is as follows:

func Bool(name string, value bool, usage string) *bool

func BoolVar(p *bool, name string, value bool, usage string)

Both define a bool flag with a specified name, default value, and usage string. The only difference is that the flag.Bool function returns a value which is the address of the bool variable that stores the value of the flag. On the other hand, the flag.BoolVar accepts an extra argument of p that points to a bool variable, in which it stores the value of the flag.

There is also a function called flag.Arg and flag.Args, shown below:

func Arg(i int) string
func Args() []string

The flag.Arg function returns the ith command-line argument. Arg(0) is the first remaining argument after flags have been processed. It returns an empty string if the requested element does not exist. The flag.Args function returns the non-flag command-line arguments.

More Code Examples of the flag Package in Go

Here is a little advanced Go code example to illustrate the usage of the flag package in Golang. The idea of the program is simple: it will have a number of sorting functions, such as quick sort, bubble sort, etc. The user will supply the list of sorting (one or more) algorithms one wants to apply to the supplied data. The data is supplied through the command line and is converted to integer type values, on which the list of sorting is performed. Note that the program is not optimized and is a quick implementation to illustrate this concept:

package main

import (
	"flag"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
)


func BubbleSort(elements []int) []int {
	for i := 0; i < len(elements)-1; i++ {
		for j := 0; j < len(elements)-1; j++ { if elements[j] > elements[j+1] {
				elements[j+1], elements[j] = elements[j], elements[j+1]
			}
		}
	}
	return elements
}

func QuickSort(elements []int) []int {
	if len(elements) < 2 {
		return elements
	}
	l, r := 0, len(elements)-1
	pivot := rand.Int() % len(elements)
	elements[pivot], elements[r] = elements[r], elements[pivot]

	for i, _ := range elements {
		if elements[i] < elements[r] {
			elements[l], elements[i] = elements[i], elements[l]
			l++
		}
	}

	elements[l], elements[r] = elements[r], elements[l]

	QuickSort(elements[:l])
	QuickSort(elements[l+1:])

	return elements
}

func SelectionSort(elements []int) []int {
	size := len(elements)
	var mindex int
	for i := 0; i < size-1; i++ {
		mindex = i
		for j := i + 1; j < size; j++ {
			if elements[j] < elements[mindex] { mindex = j } } elements[i], elements[mindex] = elements[mindex], elements[i] } return elements } type SortTypeFlag struct { SortType []string } func (s *SortTypeFlag) GetAlgoNames() []string { return s.SortType } func (s *SortTypeFlag) String() string { return fmt.Sprint(s.SortType) } func (s *SortTypeFlag) Set(v string) error { if len(s.SortType) > 0 {
		return fmt.Errorf("cannot use names flag more than once")
	}
	names := strings.Split(v, ",")
	s.SortType = append(s.SortType, names...)
	return nil
}

func main() {

	var sorting SortTypeFlag
	flag.Var(&sorting, "sort", "Comma separated list of sorting algorithm and space separated int values, eg. -sort=quick,bubble 88 33 99 55")
	flag.Parse()

	intArr := make([]int, len(flag.Args()))
	for index, val := range flag.Args() {
		intArr[index], _ = strconv.Atoi(val)
	}

	for _, item := range sorting.GetAlgoNames() {

		switch item {
		case "quick":
			fmt.Println("Quick Sort:", QuickSort(intArr))
		case "select":
			fmt.Println("Selection Sort:", SelectionSort(intArr))
		default:
			fmt.Println("(default) Bubble Sort:", BubbleSort(intArr))
		}
	}

}


You can run the program as follows:

$ go run main.go -sort=quick,bubble 67 34 98 10 76 12

Doing so will produce the following output:

Quick Sort: [10 12 34 67 76 98]
Selection Sort: [10 12 34 67 76 98]

Final Thoughts on the flag Package in Go

The flag package, although not very often used in Go, is one of the important facilities provided by the standard library especially when we want to create a UNIX/Linux system-like utility program. The package saves our time in implementing the logic of flag usages in command line programming. In fact, developing a program that uses flags cannot be simpler when this package is used efficiently.

Read more Go and Golang programming tutorials.

Source: www.developer.com