KTC MegPad 32型 4K UHD 移動式スマートモニター ( Android 13搭載 Google認証 10点タッチ Wi-Fi 6&Bluetooth 5.2 )(8GB RAM+128GB 大容量/リモコン付き/90w高速アダプター キャスター/デュアル6W*2/コードレス設計 //9500mAh内蔵バッテリー ) キッチン・リビング・寝室対応 A32Q7Pro
¥119,000 (2025年4月25日 13:07 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)USB C ケーブル 純正 1M 2本セット PD対応 60W急速充電 USBタイプc ケーブル USB-C & USBC データ転送 高耐久性 断線防止 映像出力不可 Type-c to Type-c コード for iPhone 16/15 Pro/Plus/Pro Max、for MacBook Pro/Air/IPad Pro/AirなどTypec機種対応
¥799 (2025年4月25日 13:05 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)
CLIの作成に関して個人的にブラックボックスすぎたので、表面的なとこに触れておいていざちゃんと作ろうとした時の心理的な壁をなるべく無くしておきたいと思い、試しにMarkdownで記事を書くときのちょっとしたサポートを目的としたCLIを作ってみることにしました。
実際に作ったのは、ルートコマンド サブコマンド ファイルパス
みたいな感じのコマンドで、指定したファイルの末尾に何かしらテキストを挿入するだけの超シンプルなCLIです。
例えばこんな感じです。
# コマンド
msc link ファイルパス
# 結果(指定ファイルの末尾(改行含む)
[タイトル](URL/ "")
これからGoでCLIを作ってみたいけど、そもそもCLIってどうやって作るものなのか把握しておきたい方のご参考になれば幸いです。
msc link [] タイトル付きリンクのテンプレ生成
msc details [] 詳細折りたたみのテンプレ生成
msc snip [] [] コードスニペットを追加
msc table [] テーブルのテンプレ生成
msc all [] 全テンプレ生成
msc version バージョン表示
msc help このヘルプを表示
Githubリポジトリ
ルートコマンド
package cmd
import (
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "msc [options]" ,
Short: "Markdown補助CLI(md-sup-cli)",
Long: `md-sup-cliはMarkdownの少しだけ面倒な記法のテンプレをファイル末尾に追記するCLIです。
`,
}
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
サブコマンド(一部)
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var detailsCmd = &cobra.Command{
Use: "details " ,
Short: "折りたたみ詳細をファイル末尾に追記",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
path := args[0]
snippet := `折りたたみタイトル
`
f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
fmt.Fprint(f, "nn"+snippet)
return nil
},
}
func init() {
rootCmd.AddCommand(detailsCmd)
}
Goにはcobraという簡単にCLIが作れる便利なライブラリがあるようです。
実際に使ってみます。
go install github.com/spf13/cobra-cli@latest
以下のようにして雛形が生成できます。
生成された雛形は以下のようになっていると思います。
.
├── LICENSE
├── cmd
│ └── root.go
├── go.mod
├── go.sum
└── main.go
main.go
ではcmd/root.go
のCLIエントリポイントであるExcute()
関数を実行しています。
cmd/root.goにはコマンドの作成ガイドと、実際にそのコマンドをルートコマンドに設定しCLIを起動するExcute()
があります。cmd配下で自分の作りたいコマンドを作成していくことになります。
&cobra.Command {}
コマンドを作るための構造体です。主要そうなものだとUse、Short、Long、Run、RunE、Args
など様々なCLIコマンドの設定ができるフィールドが実装されています。
RunとRunE
コマンド実行時の処理を設定できます。RunE
は返り値にerror
を返せます。エラー返したいならRunE
、標準出力だけなどエラー返すほどでもないならRun
という感じだと認識していますが、基本RunE
を使ったほうが良さそうな雰囲気を感じました。
ここまでで登場したものを扱って実装すると以下のようになります。
var versionCmd = &cobra.Command{
Use: "version",
Short: "バージョンを表示",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(cliVersion)
},
}
これは単純にCLIのバージョンを標準出力するだけのものです。このようにUse
(実際のCLIのコマンド名を定義)やShort
など、その他自分の求めている機能が表現できるフィールドを書き、上記のように書いていきます。
CLIエントリポイント
下記のコードはCLI自体の起動のためのエントリポイントです。ここでrootCmd
を指定してrootcmd
をこのCLIのルートコマンドに指定します。
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
init関数内で以下のようにすることでサブコマンドを設定できます(例:CLIでよく見るmsc snip
みたいなのができるようになる)。
ルートコマンド変数.AddCommand(サブコマンド変数)
ファイルを開き実際に書き込む
ファイルを書き込み専用で開き、書き込みたい内容をファイルの末尾に追加できるようにします。path
は書き込みたいファイルパスです。0644
は所有者は読み書きOK、他は読取りだけOKというパーミッション設定です。
f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
fは書き込み先のファイルオブジェクトで、fmtパッケージのFprint
で指定した書き込み先に文字列を出力できます。Fprint
は内部実装でWrite()
を呼び出しています。
fmt.Fprint(f, 書き込みたい内容)
デフォルトのコマンドを上書き(-h, –help)
以下のようにすることで、conbraで内部実装されている自動でヘルプを生成する関数が自動生成する内容を上書きできます。
func init() {
// SetHelpFuncで-hと--helpを上書き
rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
fmt.Print(helpText)
})
rootCmd.AddCommand(helpCmd)
}
ついでにGoReleaserを使ってビルドして生成したバイナリを配布するのもやってみました。
GoReleaserは主に以下のことをしてくれます。
- 各OS用にそれぞれビルド
- ビルドしたバイナリをOS毎に圧縮
- GitHub Releasesへのアップロード
など
まずGoReleaserの設定をします。
.goreleaser.yml
project_name: msc
release:
github:
owner: minminseo
name: md-sup-cli
builds:
- main: ./main.go
binary: msc
goos: # ここでOS指定
- linux
- darwin
- windows
goarch:
- amd64
- arm64
archives:
- format: tar.gz
次にGitHubActionsのワークフローを設定します。
流れとしては、新しいタグがPush(例:git tag v1.0.1
→git push origin v1.0.1
)されたらワークフローを起動→Ubuntu起動→ソースコードダウンロード→Goインストール→GoReleaserインストール→.goreleaser.yml
をもとにバイナリをビルドとアップロードという感じになります。
.github/workflows/release.yml
name: Release
on:
push:
tags:
- "v*.*.*"
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: "1.24"
- uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
まだ特定のファイルに文字を書き込むだけの簡単なものしかできませんが、使い方に慣れてくればもっと便利で面白そうなものが作れそうだなと思いました。
こちらの記事によると、gohugoio/hugoやx-motemen/ghqなどがGoそのものの学習においても良いそうなのでこの当たりで学んでみたいなと思います。