Subcommand
- Go course
- Intermediate
- Lesson 74/80
- 4 min
Learn to build your own subcommand structure.
Subcommands
Tools such as git commit and go build use subcommands. With the standard library a separate flag.FlagSet is set up for each subcommand and chosen by os.Args[1]:
ekleCmd := flag.NewFlagSet("ekle", flag.ExitOnError)
ad := ekleCmd.String("ad", "", "görev adı")
listeCmd := flag.NewFlagSet("liste", flag.ExitOnError)
switch os.Args[1] {
case "ekle":
ekleCmd.Parse(os.Args[2:])
fmt.Println("eklendi:", *ad)
case "liste":
listeCmd.Parse(os.Args[2:])
default:
fmt.Fprintln(os.Stderr, "bilinmeyen komut:", os.Args[1])
os.Exit(2)
}Libraries
When many subcommands, shell completion and nested commands are needed, libraries such as spf13/cobra (used by kubectl, gh, hugo) or urfave/cli are preferred. For small tools, the standard flag and a switch are enough and add no dependencies.
Practice Command dispatcher
Write calistir(args []string) string: if args[0] is "ekle", parse the -ad option with its own FlagSet and return "eklendi: " + ad; if "liste", return "liste boş"; otherwise "bilinmeyen komut". Call it with []string{"ekle", "-ad=süt"} and []string{"sil"} and print the results.
Starter code
package main
import (
"flag"
"fmt"
)
func main() {
// buraya yaz
}Sample solution
package main
import (
"flag"
"fmt"
)
func calistir(args []string) string {
switch args[0] {
case "ekle":
fs := flag.NewFlagSet("ekle", flag.ContinueOnError)
ad := fs.String("ad", "", "görev adı")
if err := fs.Parse(args[1:]); err != nil {
return err.Error()
}
return "eklendi: " + *ad
case "liste":
return "liste boş"
default:
return "bilinmeyen komut"
}
}
func main() {
fmt.Println(calistir([]string{"ekle", "-ad=süt"}))
fmt.Println(calistir([]string{"sil"}))
}Expected output
eklendi: süt bilinmeyen komut
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why is <code>os.Args[2:]</code> passed to the subcommand's FlagSet?
- [0] is the program name and [1] the subcommand; options start after that Correct answer
- Because Go requires it
- The first two arguments are always empty
- For security
Explanation: os.Args[0] is the program run and os.Args[1] the subcommand; the subcommand's own options are in the rest of the slice.
2 Subcommand set
ekleCmd := flag.____("ekle", flag.ExitOnError)
ekleCmd := flag.NewFlagSet("ekle", flag.ExitOnError)
Explanation: NewFlagSet creates an independent option set belonging to a subcommand.
3 os.Args
| Term | Meaning |
|---|---|
os.Args[0] |
Program name |
os.Args[1] |
Subcommand |
os.Args[2:] |
Subcommand options |
default branch |
Unknown command |