flagパッケージ
Golangでは,標準パッケージとしてコマンドライン引数を扱うflagパッケージが付属しています.「痒い所に手が届く」とはこのことですね.
フラグの立っていないコマンドライン引数の取得
Parse()の後にArgs()で[]stringとして取得できます.
1
2
3
4
5
6
7
8
9
10
11
12
| package main
import (
"flag"
"fmt"
)
func main() {
flag.Parse()
args := flag.Args()
fmt.Println(args)
}
|
1
2
3
4
| $ go run with-no-flag0.go a b c
[a b c]
$ go run with-no-flag0.go 1 2 3
[1 2 3]
|
$n$番目の要素のみを取り出したい場合はArg(n)でstringとして取得できます.$n$番目の要素が存在しない場合は""が返ってくるようです.
1
2
3
4
5
6
7
8
9
10
11
| package main
import (
"flag"
"fmt"
)
func main() {
flag.Parse()
fmt.Println(flag.Arg(0), flag.Arg(1))
}
|
1
2
3
4
| $ go run with-no-flag1.go hoge fuga
hoge fuga
$ go run with-no-flag1.go 1
1
|
フラグの立っているコマンドライン引数の取得
型名()もしくは型名Var()で,フラグを定義したのち,Parse()でそれぞれの変数を取得できます.
フラグの定義は「フラグ名」「デフォルト値」「ヘルプメッセージ」で行います.
型名()の場合は,指定した型へのポインタが返ってきます.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| package main
import (
"flag"
"fmt"
)
func main() {
var (
i = flag.Int("int", 0, "int flag")
s = flag.String("str", "default", "string flag")
b = flag.Bool("bool", false, "bool flag")
)
flag.Parse()
fmt.Println(*i, *s, *b)
}
|
1
2
3
4
| $ go run with-flag0.go -int 2 -str hello -bool true
2 hello true
$ go run with-flag0.go
0 default false
|
型名Var()の場合は,引数で渡した変数に代入されます.また,適切な値を渡さないと怒られます.ダメな理由も教えてくれるので怒られがいがあります.定義していないフラグも受け付けてくれません.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| package main
import (
"flag"
"fmt"
"time"
)
func main() {
var (
d time.Duration
f float64
)
flag.DurationVar(&d, "dur", 1 * time.Second, "duration flag")
flag.Float64Var(&f, "float", 0.1, "float flag")
flag.Parse()
fmt.Println(d, f)
}
|
1
2
3
4
5
6
7
8
9
10
| $ go run with-flag1.go -dur 1h -float 2.3
1h0m0s 2.3
$ go run with-flag1.go -float str
invalid value "str" for flag -float: strconv.ParseFloat: parsing "str": invalid syntax
Usage of /var/folders/.../with-flag1:
-dur duration
duration flag (default 1s)
-float float
float flag (default 0.1)
exit status 2
|
フラグの書き方
フラグの書き方は次の2通りが可能です.
ただし,Bool値を取得する場合はflag=valueを使った方がいいかもしれません.というのも, フラグの型がBool値かつ引数が続かない場合,フラグが立っただけでtrueとなるからです.
つまり,フラグを立ててBool値を取得したい場合は-bool=true/-bool=falseとしなければならないということです.-bool falseではtrueとなってしまいます.また-bool false以降の引数が全てフラグ無しで渡された引数として評価されてしまいます.注意が必要ですね.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| package main
import (
"flag"
"fmt"
)
func main() {
var (
i = flag.Int("int", 0, "int flag")
s = flag.String("str", "default", "string flag")
b = flag.Bool("bool", false, "bool flag")
)
flag.Parse()
fmt.Println(*i, *s, *b)
}
|
1
2
3
4
5
6
| $ go run with-flag0.go -bool false -int 123 -str abc # falseを含むそれ以降が全て非フラグで渡されたコマンドライン引数として扱われる
0 default true
$ go run with-flag0.go -bool=true -int 123 -str abc
123 abc true
$ go run with-flag0.go -bool=false -int 123 -str abc
123 abc false
|
ちなみに-hでヘルプを表示してくれます.賢いですね.
1
2
3
4
5
6
7
8
9
| $ go run with-flag0.go -h
Usage of /var/folders/.../with-flag0:
-bool
bool flag
-int int
int flag
-str string
string flag (default "default")
exit status 2
|
コマンドライン引数の個数を数える
NArg()で非フラグなものを,NFlag()でフラグなものをカウントできます.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| package main
import (
"flag"
"fmt"
)
func main() {
flag.Int("int", 0, "int flag")
flag.String("str", "default", "string flag")
flag.Bool("bool", false, "bool flag")
flag.Parse()
fmt.Println("non flag:", flag.NArg())
fmt.Println("flag:", flag.NFlag())
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| $ go run flag-test.go -int 1 -str foo -bool=true a b
non flag: 2
flag: 3
$ go run flag-test.go -int 1 -str foo -bool true a b
non flag: 3
flag: 3
$ go run flag-test.go -bool true -int 1 -str foo a b
non flag: 7
flag: 1
$ go run flag-test.go a b c -bool=true -str foo
non flag: 6
flag: 0
$ go run flag-test.go -bool=true -str foo a b c
non flag: 3
flag: 2
$ go run flag-test.go a b c
non flag: 3
flag: 0
$ go run flag-test.go -bool=true -str foo
non flag: 0
flag: 2
|