Go FlagSet subcommand pattern¶
The Go FlagSet subcommand pattern is a technique used to build command-line interfaces (CLI) that support distinct actions, such as get or add, each with their own specific set of flags^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md]. Instead of using a single global list of flags, this pattern leverages the flag package's FlagSet type to scope arguments to specific subcommands^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
Overview¶
Go's standard flag package implements command-line flag parsing^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md]. To handle complex tools requiring different behaviors (e.g., videos get vs videos add), developers typically create a separate FlagSet for each subcommand^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
This approach allows distinct flag definitions for different contexts. For example, a get command might accept an --id or --all flag, while an add command requires --id, --title, and --url^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
Implementation Workflow¶
1. Initialization and Validation¶
The process begins by importing the flag and os packages^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
A common validation step ensures that the user has provided enough arguments; specifically, checking if the length of os.Args is at least 2 to confirm a subcommand was intended^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
2. Defining FlagSets¶
Each subcommand is initialized using flag.NewFlagSet(name, errorHandling).
* Get Command:
getCmd := flag.NewFlagSet("get", flag.ExitOnError)
getAll := getCmd.Bool("all", false, "Get all videos")
getID := getCmd.String("id", "", "YouTube video ID")
addCmd := flag.NewFlagSet("add", flag.ExitOnError)
addID := addCmd.String("id", "", "YouTube video ID")
addTitle := addCmd.String("title", "", "YouTube video Title")
// ... other flags
3. Dispatching Logic¶
A switch statement is used to inspect os.Args[1] (the second command-line argument) to determine which subcommand to execute^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
- Case "get": Execution branches to a handler function (e.g.,
HandleGet). - Case "add": Execution branches to a handler function (e.g.,
HandleAdd). - Default: An unexpected command triggers a help message or exit^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
4. Parsing Subcommand Arguments¶
Crucially, parsing is scoped to the specific FlagSet. Instead of parsing the global os.Args, the application passes only the slice of arguments following the subcommand name^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
// Parse arguments starting from index 2 onwards
getCmd.Parse(os.Args[2:])
This ensures that flags defined for the add command do not conflict with or pollute the namespace of the get command^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
5. Execution and Validation¶
Inside the handler functions, the application validates the parsed flag values (e.g., checking if an ID is provided if --all is false) and executes the corresponding business logic^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md].
Related Concepts¶
- [[Command-line argument parsing]]
- Go programming language
- [[Software architecture patterns]]
Sources¶
^[400-devops__09-Scripting-Language__golang__introduction__part-4.commandline__readme.md]