How to parse Command Line Arguments in Go

Batuhan Bulut
6 min readMay 30, 2023

--

Beginners Guide to Parse flags (Command Line Arguments) in Go

How to parse Command Line Arguments in Go

Warming Up!

Go, (a.k.a. Golang), is an open-source programming language developed by Google.

It was designed to be efficient, concise, and easy to use while providing strong support for concurrent programming. Since Go has a lot of benefits like Simplicity, it is used by many developers currently.

Today we will be focusing on how to parse flags in Go.

Go comes with a built-in package for parsing flags, which is named “flag”(https://pkg.go.dev/flag).

We will be using the flag package for that tutorial.

Flag Package in Go

Go already provides a built-in package “flag” that simplifies the process of parsing command line flags.

With this package we can easily define, parse or access the flags in the application. Let’s dive into examples!

How to define a Flag

We can define flags as String, Integer or Boolean types.

This declares an integer flag(-int) , stored in the pointer intFlag, with type *int and default value is 1111.

import "flag"
var intFlag = flag.Int("int", 1111, "help message for flag int")

It will be also the same for other types.

We declared 2 flags (-str and -bool) stored in strFlag and boolFlag with default values.

import "flag"
var(
strFlag = flag.String("str", "<default>", "help message for strFlag")
boolFlag= flag.Bool("bool", false, "help message for boolFlag")
)

If you like, you can bind the flag to a variable using the Var() functions.

var(
intFlag int
strFlag string
boolFlag bool
)

func main() {
flag.IntVar(&intFlag, "int", 1234, "help message")
flag.StringVar(&strFlag, "str", "default" , "help message")
flag.BoolVar(&boolFlag, "bool", false, "help message")

}

Command line flag syntax

The following forms can be used for passing the values:

-flag
--flag // double dashes are also permitted
-flag=x
-flag x // non-boolean flags only

Examples

Lets use the our flags in the examples.

package main

import (
"flag"
"fmt"
)

var(
intFlag int
strFlag string
boolFlag bool
)

func main() {
flag.IntVar(&intFlag, "int", 1234, "help message")
flag.StringVar(&strFlag, "str", "default" , "help message")
flag.BoolVar(&boolFlag, "bool", false, "help message")
flag.Parse()

fmt.Println("intFlag value is: ", intFlag)
fmt.Println("strFlag value is: ", strFlag)
fmt.Println("boolFlag value is: ", boolFlag)
}

In this example;

  1. The code starts by importing the necessary packages, flag and fmt, which are part of Go's standard packages.
  2. We declared three variables: intFlag, strFlag, and boolFlag. These variables will hold the values of the corresponding command-line flags.
  3. We used the flag.IntVar, flag.StringVar, and flag.BoolVar functions to define the flags and associate them with the variables.
  4. After defining the flags, the flag.Parse() function is called to parse the command-line arguments and set the values of the corresponding variables. Must be called after all flags are defined and before flags are accessed by the program.
  5. Finally program prints the values of intFlag, strFlag, and boolFlag variables.

If we run this program without any flags, it will use the default values for variables.

go run .\main.go

//Output

intFlag value is: 1234
strFlag value is: default
boolFlag value is: false

We can send flags with arguments. Below we send flags and we can observe the output was changed.

go run .\main.go -int 12 -str hello! -bool=true


//Output

intFlag value is: 12
strFlag value is: hello!
boolFlag value is: true

Also you can execute a “-h, -help” flag for help messages for flags.

go run .\main.go -help

//Output

Usage of \go-build3444076518\b001\exe\main.exe:
-bool
help message
-int int
help message (default 1234)
-str string
help message (default "default")

If you don’t want to show “Usage of” part or customize the output you can check below:

 flag.Usage = func() {
fmt.Fprintln(os.Stderr, "Flags:")
flag.PrintDefaults()
}

What is the difference between os.Args and flag package?

In Go, os.Args and flag package are used to access command-line arguments, but they serve different purposes.

os.Args

  • os.Args” is a variable that stores all command line arguments including program name itself.
  • It’s slice of strings
  • The first element is (os.Args[0]) is the program name.
  • It will expand n times if you pass the arguments (os.Args[n])
  • os.Args can be used when you want to access all the command line arguments as a string-slice.

flag package

  • The flag package in Go provides a more sophisticated and structured approach to handle command-line arguments.
  • It allows you to define flags, specify default values, and provide help messages.
  • It supports different types of flags such as boolean, string, integer, and more.
  • The flag package handles the parsing and validation of the command-line arguments according to the defined flags.
  • It provides built-in functionality to automatically assign flag values to the associated variables.
  • It supports flag aliases, shorthand flags, and flag grouping.
  • The flag package also provides features like flag usage information, flag parsing errors, and custom flag parsing logic.
  • It simplifies the process of handling command-line arguments, especially when dealing with complex flag configurations.

We already know how to use flag package, let me give you some examples with os.Args

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("All arguments:", os.Args)

}

With this Go code we will print all arguments passed from command line:

go run .\main.go arg1 arg2 arg3

//Output
All arguments: [\main.exe arg1 arg2 arg3]

As you see we can see all the arguments we passed from command-line + program name itself.

We can parse these values as os.Args[n] since this is a slice.

What if I need to use both of them?

Let’s imagine you need a program with parse command-line arguments as flags but you also need regular arguments without flags.

We can achieve this with flag.Args() function.

  • flag.Args() is a function provided by the flag package.
  • It returns a slice of strings that contains the command-line arguments that have not been processed as flags by the flag package.
  • It excludes the program name and any flags that have been parsed using flag.Parse().
  • flag.Args() is useful when you want to access the non-flag command-line arguments specifically.

Code Example:

package main

import (
"flag"
"fmt"
"os"
)

var(
intFlag int
strFlag string
boolFlag bool
)

func main() {
flag.IntVar(&intFlag, "int", 1234, "help message")
flag.StringVar(&strFlag, "str", "default" , "help message")
flag.BoolVar(&boolFlag, "bool", false, "help message")
flag.Parse()

fmt.Println("All arguments:", os.Args)
fmt.Println("Non-flag arguments:", flag.Args())
fmt.Println("-----")
fmt.Println("intFlag value is: ", intFlag)
fmt.Println("strFlag value is: ", strFlag)
fmt.Println("boolFlag value is: ", boolFlag)
}

With this code we can parse the flags and also prints the non-flag command-line arguments.

go run .\main.go -int 1 -str hello -bool=true arg1 arg2 arg3 

//Output
All arguments: [\main.exe -int 1 -str hello -bool=true arg1 arg2 arg3]
Non-flag arguments: [arg1 arg2 arg3]
-----
intFlag value is: 1
strFlag value is: hello
boolFlag value is: true

As you see we can see everything we typed in command line as “All arguments”.

Non-Flag arguments we can see non-parsed arguments.

Important Note!

Flag parsing stops just before the first non-flag argument (“-” is a non-flag argument) or after the terminator “ — “.

It means you need to pass flags first.

If you pass the non-flag arguments first, it will not parse the flags and show them all as non-flag arguments.

go run .\main.go arg1 arg2 arg3 -int 1 -str hello -bool=true

//Output

All arguments: [\main.exe arg1 arg2 arg3 -int 1 -str hello -bool=true]
Non-flag arguments: [arg1 arg2 arg3 -int 1 -str hello -bool=true]
-----
intFlag value is: 1234
strFlag value is: default
boolFlag value is: false

In this example I passed the arg1, arg2, arg3 first.

Because of that it cannot parse the flags and show everything as non-flag arguments.

Summary

In summary, os.Args is a basic mechanism to access command-line arguments as a slice of strings,

While the flag package provides a higher-level abstraction for defining, parsing, and handling command-line flags with more control and functionality.

If you need advanced features like flag parsing, validation, and help messages, the flag package is a recommended choice.

However, if you have simple command-line arguments without any specific flag requirements, os.Args can be used for basic access to the arguments.

--

--

Batuhan Bulut

Sofware engineer, master of troubleshooting, developing stuffs in backend