Infrastructure Go daemon
SECTION 4.1

os.Args & the Flag Package

Raw Arguments

// os.Args[0] is the program name, rest are arguments
fmt.Println(os.Args[0])  // "./mytool"
fmt.Println(os.Args[1:]) // ["--config", "/etc/app.yaml"]

Fine for throwaway scripts. Not fine for real tools.

The flag Package

Standard library, no dependencies:

2 · Worked example — read every step
import "flag"

func main() {
    config := flag.String("config", "config.yaml", "path to config file")
    verbose := flag.Bool("verbose", false, "enable verbose output")
    port := flag.Int("port", 8080, "server port")
    flag.Parse()

    fmt.Printf("config=%s verbose=%t port=%d\n", *config, *verbose, *port)
    // Remaining positional args
    fmt.Println("files:", flag.Args())
}
./mytool --config /etc/app.yaml --verbose --port 9090 file1.yaml file2.yaml

When flag is enough: Single-command tools with a few options. go test itself uses the flag package.

When you need more: Subcommands (mytool lint, mytool validate), nested flags, shell completion. That's Cobra.

3 · Fill the gaps
A real tool's main — three things have to happen before the values are usable.
func main() {
    config := flag.("config", "config.yaml", "path to config file")
    verbose := flag.Bool("verbose", false, "enable verbose output")
    

fmt.Printf("config=%s verbose=%t\n", <span class="gap-slot"><input class="gap-input" data-answer="*config" size="9" spellcheck="false" autocomplete="off" autocapitalize="off"></span>, *verbose)
fmt.Println("files:", flag.<span class="gap-slot"><input class="gap-input" data-answer="Args()" size="8" spellcheck="false" autocomplete="off" autocapitalize="off"></span>)  // remaining positional args

}