This document covers FlagSet operations for creating and managing independent sets of flags, useful for implementing subcommands in CLI applications.
import "github.com/spf13/pflag"func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSetCreate a new FlagSet with specified name and error handling behavior.
Error Handling Options:
type ErrorHandling int
const (
ContinueOnError ErrorHandling = iota // Return error from Parse()
ExitOnError // Call os.Exit(2) on error
PanicOnError // panic() on error
)Usage:
// FlagSet that returns errors for manual handling
configFlags := pflag.NewFlagSet("config", pflag.ContinueOnError)
// FlagSet that exits on error (like CommandLine)
serverFlags := pflag.NewFlagSet("server", pflag.ExitOnError)
// FlagSet that panics on error
debugFlags := pflag.NewFlagSet("debug", pflag.PanicOnError)func (f *FlagSet) Name() stringReturn the name of the flag set.
func (f *FlagSet) Init(name string, errorHandling ErrorHandling)Initialize or re-initialize a FlagSet with new name and error handling.
Usage:
fs := &pflag.FlagSet{}
fs.Init("myapp", pflag.ExitOnError)func (f *FlagSet) SetOutput(output io.Writer)Set the destination for usage and error messages. If nil, os.Stderr is used.
Usage:
import "bytes"
var buf bytes.Buffer
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
fs.SetOutput(&buf) // Capture output for testingfunc (f *FlagSet) Output() io.WriterReturn the destination for usage and error messages. Returns os.Stderr if output was not set or set to nil.
All type-specific flag definers have FlagSet method equivalents. The pattern is identical to package-level functions but called on the FlagSet instance.
Usage:
fs := pflag.NewFlagSet("mycommand", pflag.ExitOnError)
// Define flags on the FlagSet
port := fs.IntP("port", "p", 8080, "server port")
verbose := fs.BoolP("verbose", "v", false, "verbose output")
config := fs.String("config", "default.conf", "config file")
fs.Parse(os.Args[1:])func (f *FlagSet) AddFlag(flag *Flag)Add a Flag struct directly to the FlagSet.
Usage:
flag := &pflag.Flag{
Name: "custom",
Shorthand: "c",
Usage: "custom flag",
Value: myCustomValue,
DefValue: "default",
}
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.AddFlag(flag)func (f *FlagSet) AddFlagSet(newSet *FlagSet)Add all flags from another FlagSet.
Usage:
// Common flags shared across subcommands
commonFlags := pflag.NewFlagSet("common", pflag.ContinueOnError)
commonFlags.Bool("verbose", false, "verbose output")
commonFlags.String("config", "default.conf", "config file")
// Subcommand-specific flags
serverFlags := pflag.NewFlagSet("server", pflag.ExitOnError)
serverFlags.Int("port", 8080, "server port")
serverFlags.AddFlagSet(commonFlags) // Include common flags
clientFlags := pflag.NewFlagSet("client", pflag.ExitOnError)
clientFlags.String("server", "localhost", "server address")
clientFlags.AddFlagSet(commonFlags) // Include common flagsfunc (f *FlagSet) Parse(arguments []string) errorParse flag definitions from the argument list. Flags can be interspersed with arguments before the "--" terminator.
Usage:
fs := pflag.NewFlagSet("myapp", pflag.ContinueOnError)
fs.String("config", "default.conf", "config file")
fs.Bool("verbose", false, "verbose output")
if err := fs.Parse(os.Args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}func (f *FlagSet) ParseAll(arguments []string, fn func(*Flag, string) error) errorParse flags from arguments and call fn for each flag with the flag and its value.
Usage:
fs := pflag.NewFlagSet("myapp", pflag.ContinueOnError)
fs.String("config", "default.conf", "config file")
err := fs.ParseAll(os.Args[1:], func(flag *pflag.Flag, value string) error {
fmt.Printf("Flag %s set to: %s\n", flag.Name, value)
// Can perform validation here
if flag.Name == "config" && value == "" {
return fmt.Errorf("config cannot be empty")
}
return nil
})func (f *FlagSet) Parsed() boolReturn true if the command-line flags have been parsed.
Usage:
if !fs.Parsed() {
fs.Parse(os.Args[1:])
}func (f *FlagSet) Lookup(name string) *FlagReturn the Flag structure of the named flag, or nil if none exists.
Usage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.Int("port", 8080, "server port")
fs.Parse(os.Args[1:])
flag := fs.Lookup("port")
if flag != nil {
fmt.Printf("Port flag value: %s\n", flag.Value.String())
fmt.Printf("Port was changed: %v\n", flag.Changed)
}func (f *FlagSet) ShorthandLookup(name string) *FlagReturn the Flag structure of the short-handed flag, or nil if none exists. Panics if len(name) > 1.
Usage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.IntP("port", "p", 8080, "server port")
flag := fs.ShorthandLookup("p")
if flag != nil {
fmt.Printf("Found flag: %s\n", flag.Name) // Prints: Found flag: port
}func (f *FlagSet) Changed(name string) boolReturn true if the flag was set on the command line (vs using default value).
Usage:
fs.String("config", "default.conf", "config file")
fs.Parse(os.Args[1:])
if fs.Changed("config") {
fmt.Println("Config explicitly set")
} else {
fmt.Println("Using default config")
}func (f *FlagSet) Set(name, value string) errorSet the value of the named flag programmatically.
Usage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.Int("port", 8080, "server port")
// Set flag before parsing
fs.Set("port", "9090")
fs.Parse(os.Args[1:])FlagSet provides type-safe getter methods for retrieving flag values. These methods return an error if the flag doesn't exist or has the wrong type.
func (f *FlagSet) GetBool(name string) (bool, error)
func (f *FlagSet) GetInt(name string) (int, error)
func (f *FlagSet) GetInt8(name string) (int8, error)
func (f *FlagSet) GetInt16(name string) (int16, error)
func (f *FlagSet) GetInt32(name string) (int32, error)
func (f *FlagSet) GetInt64(name string) (int64, error)
func (f *FlagSet) GetUint(name string) (uint, error)
func (f *FlagSet) GetUint8(name string) (uint8, error)
func (f *FlagSet) GetUint16(name string) (uint16, error)
func (f *FlagSet) GetUint32(name string) (uint32, error)
func (f *FlagSet) GetUint64(name string) (uint64, error)
func (f *FlagSet) GetFloat32(name string) (float32, error)
func (f *FlagSet) GetFloat64(name string) (float64, error)
func (f *FlagSet) GetString(name string) (string, error)
func (f *FlagSet) GetDuration(name string) (time.Duration, error)
func (f *FlagSet) GetTime(name string) (time.Time, error)
func (f *FlagSet) GetIP(name string) (net.IP, error)
func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error)
func (f *FlagSet) GetIPNet(name string) (net.IPNet, error)
func (f *FlagSet) GetBytesHex(name string) ([]byte, error)
func (f *FlagSet) GetBytesBase64(name string) ([]byte, error)
func (f *FlagSet) GetCount(name string) (int, error)
func (f *FlagSet) GetStringSlice(name string) ([]string, error)
func (f *FlagSet) GetStringArray(name string) ([]string, error)
func (f *FlagSet) GetBoolSlice(name string) ([]bool, error)
func (f *FlagSet) GetIntSlice(name string) ([]int, error)
func (f *FlagSet) GetInt32Slice(name string) ([]int32, error)
func (f *FlagSet) GetInt64Slice(name string) ([]int64, error)
func (f *FlagSet) GetUintSlice(name string) ([]uint, error)
func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error)
func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error)
func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error)
func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error)
func (f *FlagSet) GetIPNetSlice(name string) ([]net.IPNet, error)
func (f *FlagSet) GetStringToString(name string) (map[string]string, error)
func (f *FlagSet) GetStringToInt(name string) (map[string]int, error)
func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error)
func (f *FlagSet) GetText(name string, out encoding.TextUnmarshaler) errorUsage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.Int("port", 8080, "server port")
fs.StringSlice("tags", []string{}, "tags")
fs.Parse(os.Args[1:])
// Get values with type checking
port, err := fs.GetInt("port")
if err != nil {
log.Fatal(err)
}
tags, err := fs.GetStringSlice("tags")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Port: %d, Tags: %v\n", port, tags)func (f *FlagSet) Args() []stringReturn the non-flag arguments remaining after parsing.
Usage:
fs.Parse([]string{"--verbose", "file1.txt", "file2.txt"})
files := fs.Args() // []string{"file1.txt", "file2.txt"}func (f *FlagSet) Arg(i int) stringReturn the i'th argument. Arg(0) is the first remaining argument after flags have been processed.
Usage:
fs.Parse([]string{"--verbose", "input.txt", "output.txt"})
input := fs.Arg(0) // "input.txt"
output := fs.Arg(1) // "output.txt"func (f *FlagSet) NArg() intReturn the number of arguments remaining after flags have been processed.
Usage:
fs.Parse(os.Args[1:])
if fs.NArg() < 2 {
fmt.Fprintln(os.Stderr, "Error: expected at least 2 arguments")
os.Exit(1)
}func (f *FlagSet) NFlag() intReturn the number of command-line flags that have been set.
Usage:
fs.Parse(os.Args[1:])
fmt.Printf("Number of flags set: %d\n", fs.NFlag())func (f *FlagSet) ArgsLenAtDash() intReturn the length of Args at the moment when a "--" was found during parsing, or -1 if no "--" was encountered. This allows distinguishing between arguments before and after the terminator.
Usage:
fs.Parse([]string{"file1.txt", "--verbose", "--", "--not-a-flag", "file2.txt"})
dashIndex := fs.ArgsLenAtDash()
allArgs := fs.Args()
if dashIndex >= 0 {
beforeDash := allArgs[:dashIndex] // []string{"file1.txt"}
afterDash := allArgs[dashIndex:] // []string{"--not-a-flag", "file2.txt"}
}func (f *FlagSet) Visit(fn func(*Flag))Visit flags in lexicographical order (or primordial order if SortFlags is false), calling fn for each. Visits only flags that have been set.
Usage:
fs.Parse(os.Args[1:])
fmt.Println("Flags that were set:")
fs.Visit(func(flag *pflag.Flag) {
fmt.Printf(" %s = %s\n", flag.Name, flag.Value.String())
})func (f *FlagSet) VisitAll(fn func(*Flag))Visit flags in lexicographical order (or primordial order if SortFlags is false), calling fn for each. Visits all flags, even those not set.
Usage:
fmt.Println("All defined flags:")
fs.VisitAll(func(flag *pflag.Flag) {
fmt.Printf(" %s = %s (default: %s)\n",
flag.Name, flag.Value.String(), flag.DefValue)
})func (f *FlagSet) HasFlags() boolReturn true if the FlagSet has any flags defined.
Usage:
if fs.HasFlags() {
fmt.Println("FlagSet has flags defined")
}func (f *FlagSet) HasAvailableFlags() boolReturn true if the FlagSet has any flags that are not hidden.
Usage:
if fs.HasAvailableFlags() {
fs.PrintDefaults()
}func (f *FlagSet) SetInterspersed(interspersed bool)Set whether to support interspersed option/non-option arguments. When true (default), flags can appear anywhere in the arguments. When false, flag parsing stops at the first non-flag argument.
Usage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.Bool("verbose", false, "verbose output")
// Allow: myapp file1.txt --verbose file2.txt
fs.SetInterspersed(true)
// Require: myapp --verbose file1.txt file2.txt
fs.SetInterspersed(false)type FlagSet struct {
SortFlags bool // Sort flags in help/usage messages
// ...
}Control whether flags are sorted lexicographically in help output. Default is true.
Usage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.SortFlags = false // Maintain definition order in helptype FlagSet struct {
Usage func() // Function called when error occurs
// ...
}The Usage function is called when a parsing error occurs. You can set a custom function to print custom usage messages.
Usage:
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.Usage = func() {
fmt.Fprintf(os.Stderr, "Custom usage message for %s\n", fs.Name())
fs.PrintDefaults()
}type FlagSet struct {
ParseErrorsAllowlist ParseErrorsAllowlist
// ...
}
type ParseErrorsAllowlist struct {
UnknownFlags bool // Ignore unknown flags errors
}Configure an allowlist of parsing errors to ignore.
Usage:
fs := pflag.NewFlagSet("app", pflag.ContinueOnError)
fs.ParseErrorsAllowlist.UnknownFlags = true // Ignore unknown flags
// Now parsing won't fail on unknown flags
fs.Parse([]string{"--known-flag", "--unknown-flag"})Here's a complete example of using FlagSets for subcommands:
package main
import (
"fmt"
"os"
"github.com/spf13/pflag"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Expected 'server' or 'client' subcommand")
os.Exit(1)
}
// Common flags
commonFlags := pflag.NewFlagSet("common", pflag.ContinueOnError)
verbose := commonFlags.BoolP("verbose", "v", false, "verbose output")
config := commonFlags.String("config", "default.conf", "config file")
switch os.Args[1] {
case "server":
serverFlags := pflag.NewFlagSet("server", pflag.ExitOnError)
serverFlags.AddFlagSet(commonFlags)
port := serverFlags.IntP("port", "p", 8080, "server port")
serverFlags.Parse(os.Args[2:])
fmt.Printf("Starting server on port %d (verbose=%v, config=%s)\n",
*port, *verbose, *config)
case "client":
clientFlags := pflag.NewFlagSet("client", pflag.ExitOnError)
clientFlags.AddFlagSet(commonFlags)
server := clientFlags.StringP("server", "s", "localhost", "server address")
clientFlags.Parse(os.Args[2:])
fmt.Printf("Connecting to %s (verbose=%v, config=%s)\n",
*server, *verbose, *config)
default:
fmt.Fprintf(os.Stderr, "Unknown subcommand: %s\n", os.Args[1])
os.Exit(1)
}
}