Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Go言語のflagパッケージより便利というoptargを使ってみる

More than 5 years have passed since last update.

Go言語にはCLIを作るときに便利なコマンドラインオプションパーサのflagパッケージがありますが、サブコマンドを使えない等の制約があったのでoptargならできるという噂を聞きつけ、使ってみました。

https://github.com/jteeuwen/go-pkg-optarg

早速使ってみます。

main.go
package main

import (
    "fmt"
    "github.com/jteeuwen/go-pkg-optarg"
)

func main() {
    //コマンドに必要なフラグを定義
    optarg.Add("s", "source", "この引数は大事です", "")

    //値を保持する変数
    var src string

    //引数をパースします
    for opt := range optarg.Parse() {
        switch opt.ShortName {
        case "s":
            src = opt.String()
        }
    }
    fmt.Printf("sourceに指定された文字列は %s \n\n", src)
}

これを実行してみます。

$ go run main.go -s hoge
sourceに指定された文字列は hoge

$ go run main.go --source hoge
sourceに指定された文字列は hoge

$ go run main.go --sourc hoge
Unknown option '--sourc' specified.
Usage: go run main.go [options]:
 --source, -s: この引数は大事です

このようにオプションフラグが認識され、存在しない場合はUsageが表示されます。

オプションフラグがついてない引数に関してはoptarg.Parse()を実行した後にoptarg.Remainderというsliceで取得することができます。

main.go
package main

import (
    "fmt"
    "github.com/jteeuwen/go-pkg-optarg"
)

func main() {
    //コマンドに必要なフラグを定義
    optarg.Header("サブコマンド cmdA")
    optarg.Add("s", "source", "cmdAに使用するオプション", "")
    optarg.Header("サブコマンド cmdB")
    optarg.Add("P", "port", "cmdBに使用するオプション", 80)

    //引数をパースします
    ch := optarg.Parse()
    <- ch

    if len(optarg.Remainder) == 1 {
        cmd := optarg.Remainder[0]
        switch cmd {
        case "cmdA":
            cmdA()
        case "cmdB":
            cmdB()
        }
    } else {
        optarg.Usage()
    }
}

func cmdA() {
    var src string
    //引数をパースします
    for opt := range optarg.Parse() {
        switch opt.ShortName {
        case "s":
            src = opt.String()
        }
    }
    fmt.Printf("cmdAのsourceに指定された文字列は %s \n\n", src)
}

func cmdB() {
    var port int
    //引数をパースします
    for opt := range optarg.Parse() {
        switch opt.ShortName {
        case "P":
            port = opt.Int()
        }
    }
    fmt.Printf("cmdBのportに指定された文字列は %d \n\n", port)
}

これを実行すると

$ go run main.go cmdA --source hoge
cmdAのsourceに指定された文字列は hoge

$ go run main.go cmdB --port 90
cmdBのportに指定された文字列は 90

$ go run main.go
Usage: main.go [options]:

[サブコマンド cmdA]
 --source, -s: cmdAに使用するオプション

[サブコマンド cmdB]
   --port, -P: cmdBに使用するオプション (defaults to: 80)

このようにサブコマンド毎に挙動を分けることも簡単にできました。
またHelpも綺麗に表示することができて便利ですね。

また今回は試してないですが-abc等と複数のオプションフラグを繋げることも可能なようです。
詳しくは公式のREADMEを読んでみてください。

なかなかよいパッケージな気がしますね!

cyberagent
サイバーエージェントは「21世紀を代表する会社を創る」をビジョンに掲げ、インターネットテレビ局「AbemaTV」の運営や国内トップシェアを誇るインターネット広告事業を展開しています。インターネット産業の変化に合わせ新規事業を生み出しながら事業拡大を続けています。
http://www.cyberagent.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away