やること
Golangの標準パッケージであるflagを使って簡単なコマンドラインツールを作ってみます。
flagパッケージ
flagはオプションの解析やサブコマンド、ヘルプメッセージなど
コマンドラインツールの処理を簡単に実装できるような機能が提供されています。
まずは基本的な使い方から
package main
import (
"fmt"
"flag"
)
func main() {
// 左から順にオプション名、デフォルトの値、helpテキストが引数に入る
s := flag.String("s", "Hello, world!", "String help message")
flag.Parse()
fmt.Println(*s)
}
実行結果
$ go run example.go
Hello, world!
# -sオプションを付与して実行してみる
$ go run example.go -s foobar
foobar
# -hでヘルプメッセージが表示される
$ go run example.go -h
Usage of example:
-s string
String help message (default "Hello, world!")
exit status 2
型へのマッピング
flagパケージにはコマンドラインから入力された値をGoの型へマッピングする機能があります。
func main() {
strCmd := flag.String("s", "Hello, world!", "String help message")
intCmd := flag.Int("i", 1, "Int help message")
boolCmd := flag.Bool("b", false, "Bool help message")
flag.Parse()
fmt.Println("str: ", *s)
fmt.Println("int: ", *i)
fmt.Println("bool: ", *b)
}
実行結果
$ go run example.go
str: Hello, world!
int: 1
bool: false
# それぞれのオプションを付与して実行する
$ go run example.go -s foobar -i 26 -b
str: foobar
int: 26
bool: true
# -iはint型を受け取るので整数以外を渡すとエラーになります
$ go run example.go -i foo
invalid value "foo" for flag -i: strconv.ParseInt: parsing "foo": invalid syntax
Usage of example:
-b Bool help message
-i int
Int help message (default 1)
-s string
String help message (default "Hello, world!")
exit status 2
ヘルプメッセージのカスタマイズ
ヘルプメッセージをより細かく書くこともできます。
import (
"fmt"
"os"
"flag"
)
func main() {
flag.Usage = func() {
usageTxt := `Usage example [option]
An example of customizing usage output
-s, --s STRING argument, default: String help message
-i, --i INTEGER argument, default: Int help message
-b, --b BOOLEAN argument, default: Bool help message`
fmt.Fprintf(os.Stderr, "%s\n", usageTxt)
}
// 以下略
}
実行結果
$ go run example.go -h
Usage example [option]
An example of customizing usage output
-s, --s STRING argument, default: String help message
-i, --i INTEGER argument, default: Int help message
-b, --b BOOLEAN argument, default: Bool help message
exit status 2
サブコマンドを作成する
git clone
のようなサブコマンドを簡単に作れる機能も提供されています。
// 最初の引数にサブコマンドの名前を、2番目にエラーハンドリングを指定する
subCmd := flag.NewFlagSet("subcmd", flag.ExitOnError)
// エラーハンドラの種類
// flag.ContinueOnError => エラーが発生しても処理を続ける
// flag.ExitOnError => エラーが発生したらステータスコード2として終了する
// flag.PanicOnError => ランタイムパニックを発生させる
なんか作ってみる
上記の機能を利用して作成したものが以下になります。
機能的には10進数を2進数か16進数へ変換するだけです。
package main
import (
"fmt"
"flag"
"os"
"strconv"
)
func flagUsage() {
usageText := `example is an example cli tool.
Usage:
example command [arguments]
The commands are:
convhex convert Number to Hex
convbinary convert Number to binary
Use "Example [command] --help" for more infomation about a command`
fmt.Fprintf(os.Stderr, "%s\n\n", usageText)
}
func main() {
flag.Usage = flagUsage
convHexCmd := flag.NewFlagSet("convhex", flag.ExitOnError)
convBinaryCmd := flag.NewFlagSet("convbinary", flag.ExitOnError)
if len(os.Args) == 1 {
flag.Usage()
return
}
switch os.Args[1] {
case "convhex":
i := convHexCmd.Int64("i", 0, "Convert number to hex")
convHexCmd.Parse(os.Args[2:])
fmt.Println(strconv.FormatInt(*i, 16))
case "convbinary":
i := convBinaryCmd.Uint64("i", 0, "convert number to binary")
convBinaryCmd.Parse(os.Args[2:])
fmt.Println(strconv.FormatUint(*i, 2))
default:
flag.Usage()
}
}
実行結果
$ go run example.go convhex -i 11111
2b67
$ go run example.go convbinary -i 151
10010111
$ go run example.go --help
example is an example cli tool.
Usage:
example command [arguments]
The commands are:
convhex convert Number to Hex
convbinary convert Number to binary
Use "Example [command] --help" for more infomation about a command