This document covers accessing flag values after parsing, including lookups, argument access, and checking flag state.
import "github.com/spf13/pflag"func Lookup(name string) *FlagReturn the Flag structure of the named command-line flag, or nil if none exists. Operates on the global CommandLine FlagSet.
Usage:
pflag.String("output", "out.txt", "output file")
pflag.Parse()
flag := pflag.Lookup("output")
if flag != nil {
fmt.Printf("Output: %s\n", flag.Value.String())
fmt.Printf("Was changed: %v\n", flag.Changed)
fmt.Printf("Default: %s\n", flag.DefValue)
}func ShorthandLookup(name string) *FlagReturn the Flag structure of the short-handed flag, or nil if none exists. Panics if len(name) > 1.
Usage:
pflag.StringP("output", "o", "out.txt", "output file")
pflag.Parse()
flag := pflag.ShorthandLookup("o")
if flag != nil {
fmt.Printf("Found flag by shorthand: %s\n", flag.Name) // Prints: output
}func Set(name, value string) errorSet the value of the named command-line flag. Can be called before or after parsing.
Usage:
pflag.Int("port", 8080, "server port")
pflag.String("host", "localhost", "server host")
// Set defaults programmatically
pflag.Set("port", "9090")
pflag.Set("host", "0.0.0.0")
pflag.Parse() // Command-line values override programmatic values
// Or set after parsing for dynamic configuration
pflag.Parse()
if needsReset {
pflag.Set("port", "3000")
}func Parsed() boolReturn true if the command-line flags have been parsed.
Usage:
func getConfig() string {
if !pflag.Parsed() {
pflag.Parse()
}
config, _ := pflag.GetString("config")
return config
}After parsing, non-flag arguments can be accessed using Args functions.
func Args() []stringReturn the non-flag command-line arguments remaining after parsing.
Usage:
pflag.BoolP("verbose", "v", false, "verbose output")
pflag.Parse()
// Command line: myapp -v file1.txt file2.txt file3.txt
files := pflag.Args() // []string{"file1.txt", "file2.txt", "file3.txt"}
for _, file := range files {
fmt.Printf("Processing: %s\n", file)
}func Arg(i int) stringReturn the i'th command-line argument. Arg(0) is the first remaining argument after flags have been processed.
Usage:
pflag.Parse()
if pflag.NArg() >= 2 {
source := pflag.Arg(0)
dest := pflag.Arg(1)
fmt.Printf("Copying %s to %s\n", source, dest)
}func NArg() intReturn the number of arguments remaining after flags have been processed.
Usage:
pflag.Parse()
if pflag.NArg() == 0 {
fmt.Fprintln(os.Stderr, "Error: no input files specified")
os.Exit(1)
}
fmt.Printf("Processing %d files\n", pflag.NArg())func NFlag() intReturn the number of command-line flags that have been set.
Usage:
pflag.Parse()
if pflag.NFlag() == 0 {
fmt.Println("No flags specified, using all defaults")
}
fmt.Printf("%d flags were set\n", pflag.NFlag())func Visit(fn func(*Flag))Visit the command-line flags in lexicographical order (or primordial order if SortFlags is false), calling fn for each. Visits only flags that have been set.
Usage:
pflag.String("output", "out.txt", "output file")
pflag.BoolP("verbose", "v", false, "verbose mode")
pflag.Int("count", 1, "iteration count")
pflag.Parse()
fmt.Println("Flags that were set:")
pflag.Visit(func(flag *pflag.Flag) {
fmt.Printf(" --%s = %s\n", flag.Name, flag.Value.String())
})func VisitAll(fn func(*Flag))Visit the command-line 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:")
pflag.VisitAll(func(flag *pflag.Flag) {
status := "default"
if flag.Changed {
status = "set"
}
fmt.Printf(" --%s = %s (%s)\n", flag.Name, flag.Value.String(), status)
})When you have a Flag reference, you can access its fields directly:
type Flag struct {
Name string // Flag name
Shorthand string // One-letter abbreviation
Usage string // Help message
Value Value // Current value
DefValue string // Default value as text
Changed bool // Whether user set the value
NoOptDefVal string // Default when flag present without value
Deprecated string // Deprecation message
Hidden bool // Hidden from help
ShorthandDeprecated string // Shorthand deprecation message
Annotations map[string][]string // Metadata for bash completion
}Usage:
pflag.IntP("port", "p", 8080, "server port")
pflag.Parse()
portFlag := pflag.Lookup("port")
if portFlag != nil {
fmt.Printf("Name: %s\n", portFlag.Name)
fmt.Printf("Shorthand: %s\n", portFlag.Shorthand)
fmt.Printf("Value: %s\n", portFlag.Value.String())
fmt.Printf("Default: %s\n", portFlag.DefValue)
fmt.Printf("Changed: %v\n", portFlag.Changed)
fmt.Printf("Usage: %s\n", portFlag.Usage)
if portFlag.Deprecated != "" {
fmt.Printf("Deprecated: %s\n", portFlag.Deprecated)
}
}The Value field implements the Value interface for custom operations:
type Value interface {
String() string // Return string representation
Set(string) error // Parse and set value from string
Type() string // Return type name
}Usage:
pflag.StringSlice("tags", []string{}, "tags to apply")
pflag.Parse()
tagsFlag := pflag.Lookup("tags")
if tagsFlag != nil {
// Get current value
current := tagsFlag.Value.String()
fmt.Printf("Current tags: %s\n", current)
// Get type
fmt.Printf("Type: %s\n", tagsFlag.Value.Type())
// Modify value programmatically
err := tagsFlag.Value.Set("newtag1,newtag2")
if err != nil {
fmt.Printf("Error setting value: %v\n", err)
}
}Slice-type flags also implement the SliceValue interface for advanced list operations:
type SliceValue interface {
Append(string) error // Add value to end
Replace([]string) error // Replace all values
GetSlice() []string // Get all values
}Usage:
pflag.StringSlice("files", []string{}, "files to process")
pflag.Parse()
filesFlag := pflag.Lookup("files")
if filesFlag != nil {
if sv, ok := filesFlag.Value.(pflag.SliceValue); ok {
// Get current slice
current := sv.GetSlice()
fmt.Printf("Current files: %v\n", current)
// Append new value
sv.Append("newfile.txt")
// Replace all values
sv.Replace([]string{"file1.txt", "file2.txt", "file3.txt"})
}
}Before accessing a flag, you can check if it exists:
func flagExists(name string) bool {
return pflag.Lookup(name) != nil
}
// Usage
if flagExists("debug") {
debug, _ := pflag.GetBool("debug")
fmt.Printf("Debug mode: %v\n", debug)
}When accessing flags that might not exist, handle nil returns appropriately:
pflag.Parse()
// Safe access pattern
if flag := pflag.Lookup("optional-flag"); flag != nil {
fmt.Printf("Optional flag value: %s\n", flag.Value.String())
} else {
fmt.Println("Optional flag not defined")
}
// Or use Changed to check if flag was set
if pflag.Changed("optional-flag") {
value, _ := pflag.GetString("optional-flag")
fmt.Printf("User provided: %s\n", value)
} else {
fmt.Println("Using default or flag not defined")
}Here's a complete example demonstrating various access patterns:
package main
import (
"fmt"
"os"
"github.com/spf13/pflag"
)
func main() {
// Define flags
port := pflag.IntP("port", "p", 8080, "server port")
host := pflag.String("host", "localhost", "server host")
tags := pflag.StringSlice("tag", []string{}, "tags")
verbose := pflag.BoolP("verbose", "v", false, "verbose mode")
pflag.Parse()
// Access via pointers
fmt.Printf("Server will run on %s:%d\n", *host, *port)
// Check if flag was changed
if pflag.Changed("port") {
fmt.Println("Port was explicitly set")
}
// Access via Lookup
if tagsFlag := pflag.Lookup("tag"); tagsFlag != nil && tagsFlag.Changed {
fmt.Printf("Tags: %s\n", tagsFlag.Value.String())
}
// Iterate over set flags
if *verbose {
fmt.Println("\nFlags that were set:")
pflag.Visit(func(flag *pflag.Flag) {
fmt.Printf(" --%s: %s\n", flag.Name, flag.Value.String())
})
}
// Access arguments
files := pflag.Args()
if len(files) == 0 {
fmt.Fprintln(os.Stderr, "Error: no input files")
os.Exit(1)
}
fmt.Printf("\nProcessing %d files:\n", pflag.NArg())
for i, file := range files {
fmt.Printf(" %d: %s\n", i+1, file)
}
}