LoginSignup
16
10

More than 5 years have passed since last update.

Go言語でコマンドラインオプションを扱う

Posted at

コマンドラインオプションの扱い

Goでコマンドラインオプションを扱うときにはflagsパッケージを使用する。

使い方

var (
    intOpt  = flag.Int("i", 1234, "help message for \"i\" option")
    boolOpt = flag.Bool("b", false, "help message for \"b\" option")
    strOpt  = flag.String("s", "default", "help message for \"s\" option")
)

func main(){
    flag.Parse()

    fmt.Println(*intOpt)
    fmt.Println(*boolOpt)
    fmt.Println(*strOpt)
}
実行結果
$ go run main.go //何も指定しない場合はデフォルト値
1234
false
default

$ go run main.go -i 666 -b -s hello // オプションを指定した場合
666
true
hello

$ go run main.go -h  // helpも利用できる。
Usage of /tmp/go-build005022585/command-line-arguments/_obj/exe/main:
  -b    help message for "b" option
  -i int
        help message for "i" option (default 1234)
  -s string
        help message for "s" option (default "default")
exit status 2

よくある-v, --verboseみたいに省略形も指定できないか試してみた。

var (
    boolFlag   bool
    intFlag    int
    stringFlag string
)

func register() {
    flag.BoolVar(&boolFlag, "bool", false, "help message for \"b\" option")
    flag.BoolVar(&boolFlag, "b", false, "help message for \"b\" option")
    flag.IntVar(&intFlag, "int", 1234, "help message for \"i\" option (default 1234)")
    flag.IntVar(&intFlag, "i", 1234, "help message for \"i\" option (default 1234)")
    flag.StringVar(&stringFlag, "string", "defalut", "help message for \"s\" option (default \"default\")")
    flag.StringVar(&stringFlag, "s", "defalut", "help message for \"s\" option (default \"default\")")

    flag.Parse()
}

func main() {
    register()

    fmt.Println(boolFlag)
    fmt.Println(intFlag)
    fmt.Println(stringFlag)
}
$ go run main.go -h
Usage of /tmp/go-build315847528/command-line-arguments/_obj/exe/main:
  -b    help message for "b" option
  -bool
        help message for "b" option
  -i int
        help message for "i" option (default 1234) (default 1234)
  -int int
        help message for "i" option (default 1234) (default 1234)
  -s string
        help message for "s" option (default "default") (default "defalut")
  -string string
        help message for "s" option (default "default") (default "defalut")
exit status 2

う~ん...

func register() {
    flag.BoolVar(&boolFlag, "bool", false, "help message for \"b\" option")
    flag.BoolVar(&boolFlag, "b", false, "")
    flag.IntVar(&intFlag, "int", 1234, "help message for \"i\" option (default 1234)")
    flag.IntVar(&intFlag, "i", 1234, "")
    flag.StringVar(&stringFlag, "string", "defalut", "help message for \"s\" option (default \"default\")")
    flag.StringVar(&stringFlag, "s", "defalut", "")

    flag.Parse()
}
$ go run main.go -h
Usage of /tmp/go-build637651983/command-line-arguments/_obj/exe/main:
  -b
  -bool
        help message for "b" option
  -i int
         (default 1234)
  -int int
        help message for "i" option (default 1234) (default 1234)
  -s string
         (default "defalut")
  -string string
        help message for "s" option (default "default") (default "defalut")
exit status 2

ヘルプがきれいでない。

go-flags

よさげなパッケージがあったのでメモ
- https://github.com/jessevdk/go-flags
- http://godoc.org/github.com/jessevdk/go-flags

オプションを定義した構造体を用意

type Options struct{
  Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
}
  • short: 省略形(-v)
  • long: --verbose
  • description:説明

が指定できる。他にもrequired:trueにすることでオプション指定を強制できる。その他の値はこちらを参照。

次にオプションの解析

import (
    flags "github.com/jessevdk/go-flags"
)

var opts Options

func main() {
    args, err := flags.Parse(&opts)
    if err != nil {
        os.Exit(1)
    }

    // go run main.go -vv arg1 のように起動された場合、以下のように値がバインドされる
    // opts.Verbose = [true, true]
    // args[0] = "arg1"
}

helpを見てみる

$ go run main.go -h
Usage:
  main [OPTIONS]

Application Options:
  -v, --verbose  Show verbose debug information

Help Options:
  -h, --help     Show this help message

exit status 1

省略形も定義でき、表示もきれいになっている。

引数の数が足りない場合などに明示的に表示したい、Usageの内容を変更したい場合は、

func main() {
    parser := flags.NewParser(&opts, flags.Default)
    parser.Name = "pt"
    parser.Usage = "[OPTIONS] PATTERN [PATH]"

    args, _ := parser.Parse()

    // 引数がひとつもなければヘルプを表示する
    if len(args) == 0 {
        parser.WriteHelp(os.Stdout)
        os.Exit(1)
    }
}

のようにすれば良い。

以下はexample

var opts struct {
    // Slice of bool will append 'true' each time the option
    // is encountered (can be set multiple times, like -vvv)
    Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`

    // Example of automatic marshalling to desired type (uint)
    Offset uint `long:"offset" description:"Offset"`

    // Example of a callback, called each time the option is found.
    Call func(string) `short:"c" description:"Call phone number"`

    // Example of a required flag
    Name string `short:"n" long:"name" description:"A name" required:"true"`

    // Example of a value name
    File string `short:"f" long:"file" description:"A file" value-name:"FILE"`

    // Example of a pointer
    Ptr *int `short:"p" description:"A pointer to an integer"`

    // Example of a slice of strings
    StringSlice []string `short:"s" description:"A slice of strings"`

    // Example of a slice of pointers
    PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"`

    // Example of a map
    IntMap map[string]int `long:"intmap" description:"A map from string to int"`

    // Example of positional arguments
    Args struct {
        ID   string
        Num  int
        Rest []string
    } `positional-args:"yes" required:"yes"`
}

func main(){
  _, err := flags.Parse(&opts)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Verbosity: %v\n", opts.Verbose)
    fmt.Printf("Offset: %d\n", opts.Offset)
    fmt.Printf("Name: %s\n", opts.Name)
    fmt.Printf("File: %s\n", opts.File)
    fmt.Printf("Ptr: %d\n", *opts.Ptr)
    fmt.Printf("StringSlice: %v\n", opts.StringSlice)
    fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1])
    fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"])
    fmt.Printf("Args.ID: %s\n", opts.Args.ID)
    fmt.Printf("Args.Num: %d\n", opts.Args.Num)
    fmt.Printf("Args.Rest: %v\n", opts.Args.Rest)
}
ヘルプ
$ go run main.go -h
Usage:
  main [OPTIONS] ID Num Rest...

Application Options:
  -v, --verbose      Show verbose debug information
      --offset=      Offset
  -c=                Call phone number
  -n, --name=        A name
  -f, --file=FILE    A file
  -p=                A pointer to an integer
  -s=                A slice of strings
      --ptrslice=    A slice of pointers to string
      --intmap=      A map from string to int

Help Options:
  -h, --help         Show this help message

最後に

Callの使い方がわからなかった。

Call func(string) `short:"c" description:"Call phone number"`
// Callback which will invoke callto:<argument> to call a number.
// Note that this works just on OS X (and probably only with
// Skype) but it shows the idea.
opts.Call = func(num string) {
    cmd := exec.Command("open", "callto:"+num)
    cmd.Start()
    cmd.Process.Release()
}

のように使うみたいだが...

16
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
10