Go中类似于getopt的行为

17

我该如何优雅地解析程序参数列表并自动处理 "--help" 和/或 "--version"(例如 "program [-d value] [--abc] [FILE1]")在 Go 中?


1
2019年:github.com/rsc/getopt似乎是一个简单的替代方案:请参见下面的我的回答 - VonC
9个回答

24

Google已经创建了一个getopt包(import "github.com/pborman/getopt"),它提供了更标准的命令行解析功能(与“flag”包相比)。

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!

抱歉,我错了。这个程序包是由 Google 的员工编写的,版权归谷歌所有。 - yegle
新手问题 - 这会干扰位置参数吗?我假设不会。我需要再多读一些资料。 - Sridhar Sarnobat

15
使用“flag”包:http://golang.org/pkg/flag/。它不支持双破折线参数。目前还没有完全模仿GNU getopt行为的工具。

12
终于有人写了一篇。它已经发布整整一天了。 - György Andrasek
1
@Kinopiko:在源代码仓库的misc/emacs目录中查看go-mode.el。 - richq
这里是一个使用命令行标志的示例链接:http://golang.org/doc/go_tutorial.html#tmp_53(Go教程上的“Echo”示例) - Alex Reece

10

在 "命令行 UI" 部分,有几个库可以解析 getopt-long 参数

我尝试使用 Go1.0.2 版本:

示例:

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
}

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

7

go-flags非常完整,采用BSD许可证,有一个清晰的示例

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)
}

go-flags非常完整,还具有我想要的子命令功能。但是文档很难理解。我建议阅读示例代码+参考其文档是最好的选择。(您指向的示例链接非常有用。) - A-letubby

5

另一个选择是Kingping,它提供了所有你所期望的现代命令行解析库标准功能的支持。它支持多种格式的--help、子命令、要求、类型、默认值等等。它还在不断发展中。看起来这里其他的建议已经有一段时间没有更新了。

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)
  }
}

并且--help的输出结果:

$ 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.

5
我为你特别制作了这个:
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])
    }
  }
}

参见 https://play.golang.org/p/XtNXG-DhLI

测试:

$ ./8.out -help -version monkey business
我需要某人
版本零
参数 3: 猴子
参数 4: 生意

这段代码不支持标志参数(如 OP 的 -d value)或默认值;如果程序员自己编写,他们不太可能满足用户的期望(如 --key value--key=value 的等效性)。手动编写 --help 使得生成制表完成变得困难,并需要手动维护空间分散的代码。真正的代码可能应该将 Args 分成标志及其值和非标志参数两部分。当新手询问有关像参数解析这样棘手但基本的问题时,正确的答案不是“自己编写”。 - Jeff Schwab

3

2
作为一个简单的库,自2017年8月起你可以在 github.com/rsc/getopt 上使用它。
要使用该库,请像平常一样使用 flag 包定义标志。然后通过调用 getopt.Alias 来引入任何别名。
getopt.Alias("v", "verbose")

或者调用getopt.Aliases来定义一个别名列表:
最初的回答
getopt.Aliases(
    "v", "verbose",
    "x", "xylophone",
)

并且:

一般来说,对于新程序,推荐使用 Go 的标志解析,因为它不会太过于拘谨于调用标志时使用的破折号数量(你可以写 -verbose--verbose,程序不会在意)。

该包旨在用于需要使用完全遵循 getopt(3) 语法的情况,例如在使用 Go 重写已经使用 getopt(3) 的现有工具时。


0

可以简单地使用Golang自带的库“flag”。

它有相当多的代码可以在GoLang中创建类似CLI的应用程序。例如:

srcDir := flag.String("srcDir", "", "Source directory of the input csv file.")

上面的标志库字符串方法将期望从命令提示符中接收一个参数。

请前往https://golang.org/pkg/flag/进行更多阅读。

愉快的学习...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接