Question

How do I nicely parse a list of program parameters and automate handling "--help" and/or "--version" (such as "program [-d value] [--abc] [FILE1]") in Go?

Was it helpful?

Solution 5

I made it just for you:

package main

import (
  "fmt";
  "os"
)

func main() {
  for i, arg := range os.Args {
    if arg == "-help" {
      fmt.Printf ("I need somebody\n")
    }else if arg == "-version" {
      fmt.Printf ("Version Zero\n")
    } else {
      fmt.Printf("arg %d: %s\n", i, os.Args[i])
    }
  }
}

see also https://play.golang.org/p/XtNXG-DhLI

Test:

$ ./8.out -help -version monkey business
I need somebody
Version Zero
arg 3: monkey
arg 4: business

OTHER TIPS

Use the 'flag' package: http://golang.org/pkg/flag/. It doesn't do double-dash arguments, however. There isn't anything that exactly mimics GNU getopt behaviour (yet.)

Google has created a getopt package (import "github.com/pborman/getopt") which provides the more standard command line parsing (vs the 'flag' package).

package main

import (
    "fmt"
    "os"
    "github.com/pborman/getopt"
)

func main() {
    optName := getopt.StringLong("name", 'n', "", "Your name")
    optHelp := getopt.BoolLong("help", 0, "Help")
    getopt.Parse()

    if *optHelp {
        getopt.Usage()
        os.Exit(0)
    }

    fmt.Println("Hello " + *optName + "!")
}

 

$ ./hello --help
Usage: hello [--help] [-n value] [parameters ...]
     --help        Help
 -n, --name=value  Your name

$ ./hello --name Bob
Hello Bob!

From the section "Command Line UI", you have several libraries able to parse getopt-long parameters.

I tried, with a Go1.0.2:

Example:

package main

import (
    "fmt"
    goopt "github.com/droundy/goopt"
)

func main() {
    fmt.Println("flag")
    goopt.NoArg([]string{"--abc"}, "abc param, no value", noabc)

    goopt.Description = func() string {
        return "Example program for using the goopt flag library."
    }
    goopt.Version = "1.0"
    goopt.Summary = "goopt demonstration program"
    goopt.Parse(nil)
}

func noabc() error {
    fmt.Println("You should have an --abc parameter")
    return nil
}

Other default parameters provided with goopt:

 --help               Display the generated help message (calls Help())
 --create-manpage     Display a manpage generated by the goopt library (uses Author, Suite, etc)
 --list-options       List all known flags

go-flags is very complete, BSD licensed, and has a clear example.

var opts struct {
      DSomething string `short:"d" description:"Whatever this is" required:"true"`
      ABC bool `long:"abc" description:"Something"`
}

fileArgs, err := flags.Parse(&opts)

if err != nil {
    os.Exit(1)
}

Another option is Kingping which provides support for all the standard goodies you have come to expect from a modern command line parsing library. It has --help in multiple formats, sub-commands, requirements, types, defaults, etc. It's also still under development. It seems like the other suggestions here haven't been updated in a while.

package main

import (
  "os"
  "strings"
  "gopkg.in/alecthomas/kingpin.v2"
)

var (
  app      = kingpin.New("chat", "A command-line chat application.")
  debug    = app.Flag("debug", "Enable debug mode.").Bool()
  serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").IP()

  register     = app.Command("register", "Register a new user.")
  registerNick = register.Arg("nick", "Nickname for user.").Required().String()
  registerName = register.Arg("name", "Name of user.").Required().String()

  post        = app.Command("post", "Post a message to a channel.")
  postImage   = post.Flag("image", "Image to post.").File()
  postChannel = post.Arg("channel", "Channel to post to.").Required().String()
  postText    = post.Arg("text", "Text to post.").Strings()
)

func main() {
  switch kingpin.MustParse(app.Parse(os.Args[1:])) {
  // Register user
  case register.FullCommand():
    println(*registerNick)

  // Post message
  case post.FullCommand():
    if *postImage != nil {
    }
    text := strings.Join(*postText, " ")
    println("Post:", text)
  }
}

And the --help output:

$ chat --help
usage: chat [<flags>] <command> [<flags>] [<args> ...]

A command-line chat application.

Flags:
  --help              Show help.
  --debug             Enable debug mode.
  --server=127.0.0.1  Server address.

Commands:
  help [<command>]
    Show help for a command.

  register <nick> <name>
    Register a new user.

  post [<flags>] <channel> [<text>]
    Post a message to a channel.

I think what you want is docopt. I'll just refer you to an earlier answer I posted for the details.

As a simple library, you have since August 2017 github.com/rsc/getopt

To use, define flags as usual with package flag. Then introduce any aliases by calling getopt.Alias:

getopt.Alias("v", "verbose")

Or call getopt.Aliases to define a list of aliases:

getopt.Aliases(
    "v", "verbose",
    "x", "xylophone",
)

And:

In general Go flag parsing is preferred for new programs, because it is not as pedantic about the number of dashes used to invoke a flag (you can write -verbose or --verbose, and the program does not care).

This package is meant to be used in situations where, for legacy reasons, it is important to use exactly getopt(3) syntax, such as when rewriting in Go an existing tool that already uses getopt(3).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top