Command-Line Subcommands
flag.NewFlagSet creates a per-subcommand flag set, enabling tools with subcommands like "git commit" or "docker run" where each subcommand has its own flags.
flag.NewFlagSet creates an independent parser for a command. Read the first argument to choose a command, then parse the remaining arguments with its flag set.
Each subcommand can define flags with its own names and defaults. Check that a command was supplied before accessing os.Args[1].
package main
import (
"flag"
"fmt"
"os"
)
func main() {
build := flag.NewFlagSet("build", flag.ExitOnError)
output := build.String("output", "app", "binary name")
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: tool build [flags]")
os.Exit(1)
}
if os.Args[1] != "build" {
fmt.Fprintln(os.Stderr, "unknown command:", os.Args[1])
os.Exit(1)
}
build.Parse(os.Args[2:])
fmt.Println("building", *output, "with args", build.Args())
}In production
FlagSet is enough for a small CLI. Keep command behavior in functions that accept an argument slice and return an error; this makes commands easier to test without changing process-wide os.Args.
Enjoyed this? Get more software craft delivered to your inbox.