CodeBlanks Logo Icon CodeBlanks

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.

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

main.go
package main

import (
    "flag"
    "fmt"
)

func main() {
    // buraya yaz
}

Sample solution

main.go
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

Question
ekleCmd := flag.____("ekle", flag.ExitOnError)
Answer
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

All lessons in Intermediate