Help us understand the problem. What is going on with this article?

Goでflagを使ってコマンドライン引数を扱う

More than 1 year has passed since last update.

多分一億番煎じくらいの内容:tea:
記事としての価値はまあ置いといて:raised_hand:
せっかくやったので整理のために書きます:bulb:

公式ドキュメント
https://golang.org/pkg/flag/

非フラグの取得

Parse()を呼んだ後にArgs()[]stringとして取得できます。

sample1_1.go
package main

import (
    "flag"
    "fmt"
)

func main() {
    flag.Parse()
    args := flag.Args()
    fmt.Println(args)
}
実行例1-1
$ go run sample1_1.go a b c
[a b c]

$ go run sample1_1.go 1 2 3
[1 2 3]

特定の要素だけ取り出したい場合はArg(int)が使えます。こちらもstringとして取り出します。

sample1_2.go
package main

import (
    "flag"
    "fmt"
)

func main() {
    flag.Parse()
    fmt.Println(flag.Arg(0), flag.Arg(1))
}
実行例1-2-1
$ go run sample1_2.go hoge fuga
hoge fuga

範囲外アクセスしたつもりが落ちたりはしませんでした。空文字列が返ってくるっぽいです。

実行例1-2-2
$ go run sample1_2.go 1
1

フラグの取得

型名()あるいは型名Var()でフラグの定義をした後Parse()でそれぞれの変数に取得できます。
定義は(フラグ名、デフォルト値、ヘルプメッセージ)の3つからなります。
型名()を使った場合、指定した型のポインタが返ってきます。

sample2_1.go
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)
}
実行例2-1-1
$ go run sample2_1.go -int 2 -str hello -bool true
2 hello true

フラグが指定されない場合はデフォルト値が入ります。

実行例2-1-2
$ go run sample2_1.go
0 default false

型名Var()を使った場合、引数で渡した変数にバインドされます。

sample2_2.go
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)
}
実行例2-2-1
$ go run sample2_2.go -dur 1h -float 2.3
1h0m0s 2.3

パースできない値を渡すと怒られます。駄目な理由を教えてくれるので親切です。ついでにフラグの種類とデフォルト値も表示してくれます。

実行例2-2-2
$ go run sample2_2.go -float str
invalid value "str" for flag -float: strconv.ParseFloat: parsing "str": invalid syntax
Usage of (略):
  -dur duration
        duration flag (default 1s)
  -float float
        float flag (default 0.1)

定義していないフラグを渡しても怒られます。

実行例2-2-3
$ go run sample2_2.go -unkown yeah
flag provided but not defined: -unkown
(以下略)

フラグの書き方は-flag valueでも-flag=valueでも大丈夫です。ただしboolの場合は-flag=valueの形式を使ったほうが良いみたいです(下の実行例3参照)。

実行例2-2-4
$ go run sample2_2.go -dur=1m -float .5
1m0s 0.5

-hでヘルプを表示できます。

実行例2-2-5
$ go run sample2_2.go -h
Usage of (略):
  -dur duration
        duration flag (default 1s)
  -float float
        float flag (default 0.1)

個数を数える

非フラグはNArg()、フラグはNFlag()でそれぞれ個数を数えられます。

sample3.go
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(flag.NArg(), flag.NFlag())
}
実行例3
$ go run sample3.go -int 1 -str foo -bool=true a b
2 3

$ go run sample3.go -int 1 -str foo -bool true a b
3 3

$ go run sample3.go -bool true -int 1 -str foo a b
7 1

$ go run sample3.go a b c -bool=true -str foo
6 0

$ go run sample3.go -bool=true -str foo a b c 
3 2

$ go run sample3.go a b c 
3 0

$ go run sample3.go -bool=true -str foo
0 2

フラグがboolかつ後ろに引数が続く場合、-flag=valueの形式で書かないとフラグの値として認識してくれませんでした。
また、非フラグはフラグより後ろに書かないといけないみたいです。

おわりに

flag超便利だな!!!って思いました:sparkles:
今までコマンドライン引数って文字列を頑張ってパースしないといけないものだとばかり思っていたもので:sweat_smile:
言語にあらかじめこういったパッケージが用意されているのはホント素晴らしい:tada:

Yaruki00
主にiOSエンジニアとしてSwiftを書いています。 たまにアプリで使うAPIなりバッチなりをPHPとかGoとかPythonとかで書いたりもします。 設計に興味があり、最近はもっぱらMVVMを使っています。 あと、画像認識をやろうとPythonで機械学習のライブラリをちょっと触ってます。
andfactory
Smartphone Idea Companyとして、人々の生活に「&(アンド)」を届ける。
https://andfactory.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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした