flagパッケージでコマンドラインフラグが現れたか確認する方法
Goflagパッケージを使うと、コマンドラインフラグ(オプション)を便利に扱うことができます。
flagパッケージを使っていて、あるフラグがコマンドラインに現れたかどうかを検知したいという状況があったので、方法を調べてみました。
一つ目の方法はコマンドラインの内容を os.Args
で直接調べる方法です。ただし、flagパッケージで作られるフラグは、例えば a
という名前のフラグならば -a
と --a
という2つの形式がある上に、引数を持つ場合、 -a x
と -a=x
という2つの形式があるため、処理が複雑になってしまうかもしれません。また、osパッケージを使うのはあまりスマートな方法ではないと思います。
二つ目の方法は、フラグのデフォルトの値から変更があるかをチェックする方法です。これが一番普通の方法だと思います。しかし、コマンドラインでデフォルトと同じ値をセットした場合と、コマンドラインにそのフラグが現れていない場合の区別はつきません。
三つ目の方法は、 flag.Visit()
という関数を使う方法です。 flagパッケージ内の関数を使って調べるには、これしかないようです。flag.Visit()
に渡す関数を定義する必要がありますが、今回の目的には一番あっているようです。
上記の三つの方法を示すコードを作成してみました。
同じような状況があった場合は、この三つの方法をうまく使いわけるといいと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// flag package example package main import ( "flag" "fmt" "os" ) const strflagName = "strtest" const boolflagName = "booltest" const strflagDefValue = "defaultstr" const boolflagDefValue = false var strflag = flag.String(strflagName, strflagDefValue, "string test flag") var boolflag = flag.Bool(boolflagName, boolflagDefValue, "boolean test flag") // Flag の Name, Value を表示する関数 func printFlag(flg *flag.Flag) { fmt.Printf("%v: %v\n", flg.Name, flg.Value) } func main() { // コマンドラインをすべて表示する。 fmt.Println(os.Args) flag.Parse() // デフォルトの値から変更があるかチェックする。 if strflagDefValue != *strflag { fmt.Printf("%v value changed: %v -> %v\n", strflagName, strflagDefValue, *strflag) } if boolflagDefValue != *boolflag { fmt.Printf("%v value changed: %v -> %v\n", boolflagName, boolflagDefValue, *boolflag) } // Lookup() を使った方法 // Flag.Value は Value型なので、String()を呼び出す。 if flg := *flag.Lookup(strflagName); flg.DefValue != flg.Value.String() { fmt.Printf("%v value changed: %v -> %v\n", strflagName, flg.DefValue, flg.Value.String()) } if flg := *flag.Lookup(boolflagName); flg.DefValue != flg.Value.String() { fmt.Printf("%v value changed: %v -> %v\n", boolflagName, flg.DefValue, flg.Value.String()) } // Visit はコマンドラインの各 flag に対して辞書順に fn を呼び出す。 // セットされた flag のみを処理する。 fmt.Println("\nflag.Visit:") flag.Visit(printFlag) // VisitAll はコマンドラインの各 flag に対して辞書順に fn を呼び出す。 // セットされていなくても、すべての flag を処理する。 fmt.Println("\nflag.VisitAll:") flag.VisitAll(printFlag) } |
参考文献
- 「プログラミング言語Go」 Alan A.A. Donovan (著), Brian W. Kernighan (著), 柴田 芳樹 (翻訳)