🖥️

urfave/cli でちょっとしたコマンドラインアプリを作る

2025/02/24に公開

今回作るもの

Python で言うところの argparse を Golang でもやりたい。なので、今回は urfave/cli を用いてかなり argparse に近いものを作ってみる。

tl;dr

大体以下の通りのコードを実装すれば良い。
https://gist.github.com/ARGI-BERRI/e9dcaeb8cf5f43997559bcd220386d59#file-a-go

このコードでは単純に -f でファイル名を受け取り標準出力にファイル名を出力するアプリを実装した。もちろん --help を渡せばヘルプテキストが表示される。

実際に作ってみた

依存パッケージの追加

go get github.com/urfave/cli/v3

必要最小限な部分の実装

argparse で言うところの ArgumentParser を宣言するらへんの部分を実装する。NameUsage も最終的に --help 引数を与えると表示されるヘルプテキストに表示される。

package main

import (
	"context"
	"github.com/urfave/cli/v3"
	"os"
)

func main() {
	cmd := &cli.Command{
		Name:  "Sample App",
		Usage: "A sample app with urfave/cli",
	}

	if err := cmd.Run(context.Background(), os.Args); err != nil {
		return
	}
}

ビジネスロジックの追加

&cli.CommandAction にスライスとして引数を追加できる。多少複雑なロジックを組む場合は無名関数の中で別の関数を呼び出すことになるだろう。

	cmd := &cli.Command{
		Action: func(ctx context.Context, command *cli.Command) error {
			fmt.Println("Hello")
			return nil
		},
	}

なお、urface/cli はサブコマンドもサポートしている。ただこの記事では触れない。

コマンド引数の追加

&cli.CommandFlags にスライスとして引数を追加できる。以下は文字列を受け取るフラグの例である。

  • Name: フラグ名。例えば下記の例ではフラグは --file <file> で指定することになる。
  • Aliases: エイリアス。下記の例では -f <file> と書けるようになる。
  • Usage: ヘルプテキストに表示される説明書き。
  • Destination: フラグで受け取った値をバインドする変数。下記の例では、-f a.txt とした場合、filePath には a.txt が代入されることになる。
	var filePath string

	cmd := &cli.Command{
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:        "file",
				Aliases:     []string{"f"},
				Usage:       "Path to random file",
				Destination: &filePath,
			},
		},
	}

公式ドキュメントのフラグの説明を見れば分かる通り、他にも必須フラグの指定だったりフラグに与えられた値に対するバリデーション的なこともできる。

*cli.Command から Args として直接渡された引数を見ることも出来るが、ややこしいことをするならフラグで受け取るのが見通しが良いように思える。

参考リンク

Discussion