Go
Subcommand
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.
Exercise 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.
Show example 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"}))
}
Test yourself
-
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
- Because Go requires it
- The first two arguments are always empty
- For security
Show answer
[0] is the program name and [1] the subcommand; options start after that — 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.
-
Subcommand set
ekleCmd := flag.____("ekle", flag.ExitOnError)
Show answer
ekleCmd := flag.NewFlagSet("ekle", flag.ExitOnError)
-
os.Args
- os.Args[0]
- Program name
- os.Args[1]
- Subcommand
- os.Args[2:]
- Subcommand options
- default branch
- Unknown command
Next lesson: os.Args