Go でコマンドラインツールを作るときに便利なパッケージ
こんにちは、 Zaim でサーバーサイドエンジニアをしている @hira です。
少し前に、単純作業を手軽に自動化できたら便利だと思い、コマンドラインツールを作成することにしました。個人的に Go が好きなのとコマンドラインツールを作るための機能が標準で用意されているので Go で作ることにしました。
今回は、その中で私自身が実際に利用して便利だと感じた Go のパッケージについて共有したいと思います。
Go でコマンドラインツールを作るメリット 3 つ
パッケージを紹介する前にコマンドラインツールを Go で作って感じたメリットを挙げたいと思います。
シングルバイナリになる
まず 1 つ目のメリットは Go でコードをコンパイルするとシングルバイナリになる点が挙げられます。シングルバイナリであれば、実行環境で処理系などを用意せずに利用できるツールを作成できるため、ツールを使う側の人にとって大きなメリットになります。
クロスプラットフォーム向けにビルドできる
2 つ目のメリットは、Go で書いたコードは簡単にクロスコンパイルできる点です。例えば macOS 上で Windows や Linux 向けのバイナリをクロスコンパイルするには以下のように GOOS や GOARCH の環境変数を設定するだけです。
# Windows (32 ビット)向けにコンパイル
$ GOOS=windows GOARCH=386 go build
# Linux(64 ビット)向けにコンパイル
$ GOOS=linux GOARCH=amd64 go build
別の開発環境を使っている人向けにコンパイルできる点は、コマンドラインツールを作る上で大きなメリットだと思います。
Go は標準パッケージが充実している
3 つ目のメリットとして標準パッケージが充実している点が挙げられます。コマンドラインツールには、プログラムに対してオプションを指定するためのフラグを設定するケースが多いと思います。Go ではフラグを設定するために使う flag パッケージが標準で用意されています。簡単なコマンドラインツールであれば、外部パッケージを使わずに開発できます。
コマンドラインツールを作成する際に便利だったパッケージ
私自身が使ってみて便利だと感じた Go のパッケージについて紹介したいと思います。
flag パッケージ
flag パッケージはコマンドラインツールのフラグを設定するためのパッケージです。標準パッケージなので Go をインストールすれば使うことができます。
flag パッケージでフラグを扱うには 2 つの方法があるので、それぞれの方法について紹介したいと思います。
1. 変数を定義してフラグを変数に束縛する方法
型ごとに用意されている Var() 関数を使うことで、フラグを変数に束縛できます。
第一引数にポインタを渡す点だけ注意が必要です。これは Parse() 関数を呼び出すタイミングで、初期化済みの変数にフラグの値を格納する必要があるためです。
以下のコードは受け取ったフラグをそのまま出力する例です。
package main
import (
"flag"
"fmt"
)
var i int
var s string
var b bool
func init() {
// Var() 関数の引数は以下の通り
// 第一引数は束縛する変数のポインタ
// 第二引数はフラグ名
// 第三引数はデフォルト値
// 第四引数はフラグの説明
flag.IntVar(&i, "i", 0, “数値” )
flag.StringVar(&s, "s", "", "文字列")
flag.BoolVar(&b, "b", false, "真偽値")
}
func main() {
flag.Parse()
fmt.Println(i, s, b)
}
実行結果
フラグなし(デフォルト値が使われる)
フラグあり
2. フラグをポインタで受け取る方法
flag パッケージで定義されている Int() String() Bool() を使うことで予め変数を定義しなくてもフラグをポインタで受け取ることができます。
返ってくる値がポインタになることに注意が必要です。これは 1 で紹介した変数を束縛する方法と同様の理由で、 Parse() 関数を呼び出したタイミングでフラグの値を格納する必要があるためです。
以下のコードは受け取ったフラグをそのまま出力する例です。
package main
import (
"flag"
"fmt"
)
func main() {
// Int() 、 String() 、 Bool() 関数の引数は以下の通り
// 第一引数はフラグ名
// 第二引数はデフォルト値
// 第三引数はフラグの説明
var i = flag.Int("i", 0, "数値")
var s = flag.String("s", "", "文字列")
var b = flag.Bool("b", false, "真偽値")
flag.Parse()
// 返ってくる値はポインタのためデリファレンスする
fmt.Println(*i, *s, *b)
}
実行結果は 1 と同じになります。
color パッケージ
color は標準出力に色をつけられるパッケージです。
標準パッケージではないため go get コマンドでインストールする必要があります。
$ go get github.com/fatih/color
出力したい色ごとに関数が定義されており、関数に文字列を渡すだけで標準出力に色をつけてくれます。
以下は緑色、赤色、黄色に標準出力する例です。
package main
import (
"github.com/fatih/color"
)
func main() {
// 緑色で「Green」が出力されます
color.Green("Green")
// 赤色で「Red」が出力されます
color.Red("Red")
// 黄色で「Yellow」が出力されます
color.Yellow("Yellow")
}
実行結果
フォーマットを指定したい場合は、 color の関数をラップした関数を作ると便利です!
package main
import (
"fmt"
"github.com/fatih/color"
)
func Greenf(t string, args ...interface{}) {
color.Green(fmt.Sprintf(t, args...))
}
func Redf(t string, args ...interface{}) {
color.Red(fmt.Sprintf(t, args...))
}
func Yellowf(t string, args ...interface{}) {
color.Yellow(fmt.Sprintf(t, args...))
}
func main() {
i := 123
// 緑色で「Green 123」が出力されます
Greenf("Green %d", i)
// 赤色で「Red 123」が出力されます
Redf("Red %d", i)
// 黄色で「Yellow 123」が出力されます
Yellowf("Yellow %d", i)
}
実行結果
上記で紹介した色以外も用意されているので、興味がある方は README.md を確認して見てください!
spinner パッケージ
spinner はインジケーターを表示するためのパッケージです。
spinner パッケージも標準パッケージではないため go get コマンドでインストールする必要があります。
$ go get github.com/briandowns/spinner
使い方はとても簡単で Spinner 構造体の Start() メソッドを使ってインジケータを表示を開始し、Stop() メソッドで停止できます。
表示したいインジケーターは spinner.New() 関数の第一引数で設定します。
以下は 5 秒間インジケーターを表示するための例です。
package main
import (
"time"
"github.com/briandowns/spinner"
)
func main() {
s := spinner.New(spinner.CharSets[11], 100*time.Millisecond)
s.Start()
time.Sleep(5 * time.Second)
s.Stop()
}
実行結果
コマンドラインツールの処理が長い場合は、インジケーターを追加することをおすすめします。
spinner ではインジケーターが 44 種類あり、 README.md で確認できます。是非、気に入ったものを設定してみてください!
最後に
今回は、コマンドラインツールを作るときに便利なパッケージを共有させていただきました。私自身 Go でコマンドラインツールを作ってみて、 Go はサーバーサイドのアプリケーションを書くだけでなく、コマンドラインツールのようなプログラムにも最適な言語だと感じました。今後も機会があれば Go を使ってコマンドラインツールを作りたいと思います。
Zaim では、エンジニアを募集しています。ぜひ話を聞きに来てください!