Skip to content
Go Basics: Parse CLI Options Without Exiting the Process

Go Basics: Parse CLI Options Without Exiting the Process

October 31, 2026

CLI parsing is easier to test when it returns an error instead of terminating the whole program. Parse a supplied argument slice and handle both syntax errors and application-level constraints.

Prepare a scratch directory

Tested on Linux amd64 with Go 1.26.10. Install Go and make go available on PATH. You also need Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The example uses only the standard library and needs no module or external dependency.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

Run the example

Save this as flagset-validation-demo.go:

package main

import (
	"flag"
	"fmt"
	"io"
)

func parse(args []string) (int, []string, error) {
	flags := flag.NewFlagSet("batch", flag.ContinueOnError)
	flags.SetOutput(io.Discard)
	count := flags.Int("count", 1, "number of repetitions")
	if err := flags.Parse(args); err != nil {
		return 0, nil, err
	}
	if *count < 1 || *count > 10 {
		return 0, nil, fmt.Errorf("count must be 1..10")
	}
	return *count, flags.Args(), nil
}
func main() {
	for _, args := range [][]string{{"-count=3", "report.txt"}, {"-count=0"}, {"-unknown"}, {"--", "-report.txt"}} {
		count, files, err := parse(args)
		fmt.Printf("%q: accepted=%t count=%d files=%q\n", args, err == nil, count, files)
	}
}

Run it:

go run flagset-validation-demo.go

Observed output:

["-count=3" "report.txt"]: accepted=true count=3 files=["report.txt"]
["-count=0"]: accepted=false count=0 files=[]
["-unknown"]: accepted=false count=0 files=[]
["--" "-report.txt"]: accepted=true count=1 files=["-report.txt"]

Read the result

ContinueOnError lets the caller handle parse failures. Syntax validation accepts a numeric zero, so the separate range check is necessary. The -- separator ends option parsing, allowing a positional filename beginning with a hyphen. Diagnostics are suppressed here to keep the test report compact.

Apply it carefully

A real CLI should display useful errors and choose an appropriate exit status. Standard flag parsing stops at the first non-flag argument; it does not automatically support intermixed options and filenames. Decide how help requests, required positionals, and repeated flags should behave.

The official Go reference documents the behavior used here.

Clean up

Remove the saved source, return to the starting directory, and remove the empty practice directory. go run does not leave an executable here; Go manages its build cache separately.

rm -- flagset-validation-demo.go
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on