最近、派手なAIツールよりも、30分で書いた小さなGoのCLIのほうを何度も叩いています。WindowsをメインPCにしていると、ちょっとした確認のたびにブラウザを開いたり、設定画面を掘ったり、妙に重いGUIを待ったりする場面があります。そういう無駄な数秒が私はかなり嫌いです。
先日も、ダウンロードフォルダに今日触ったファイルだけを時刻順で見たくなりました。Explorerでもできますが、並び替えとフィルタを毎回触るのが面倒でした。そこでGoで小さなCLIを書きました。再帰的にファイルを拾って、更新時刻の新しい順に5件だけ出すだけです。やっていることは雑です。でも、こういう雑な道具ほど残ります。
30行の道具は、思ったより長く使います
下のコードです。go run recentfiles.go <directory> で動きます。私はWindows側のフォルダをWSL2から渡して使うことが多いですが、Linuxでもそのまま動きます。記事に載せる以上さすがに口だけではまずいので、確認に使ったコマンドもそのまま置いておきます。
docker run --rm -v "$PWD":/work -w /work golang:1.24 go run recentfiles.go demo
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"time"
)
type entry struct {
name string
mod time.Time
}
func main() {
dir := "."
if len(os.Args) > 1 {
dir = os.Args[1]
}
list := make([]entry, 0)
filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
if err != nil || d.IsDir() {
return nil
}
info, err := d.Info()
if err != nil {
return nil
}
list = append(list, entry{name: path, mod: info.ModTime()})
return nil
})
sort.Slice(list, func(i, j int) bool {
return list[i].mod.After(list[j].mod)
})
limit := 5
if len(list) < limit {
limit = len(list)
}
for _, f := range list[:limit] {
fmt.Printf("%s\t%s\n", f.mod.Format("2006-01-02 15:04"), f.name)
}
}
この手のCLIは、できることが少ないのがむしろ良いです。設定画面もなければ、ログインも通知もありません。引数を渡したら一行ずつ返して終わりです。朝の頭には、そのくらい鈍さのない道具がちょうど合います。
AIにこういう道具の叩き台を書かせるのはかなり相性がいいです。ファイルを走査する、整形して出す、終了コードを返す。その程度なら、面倒な指の運動は任せてしまって構いません。こちらは何を見たいかだけ決めれば足ります。最近のプログラミングで気持ちいいのはそこです。フレームワークの機嫌を取ることではなく、考えるべきところだけ自分で握れることです。
Goは、いま一番まともな道具言語だと思っています
こういう小さなCLIを書くとき、私はかなりの頻度でGoを選びます。起動が速いです。標準ライブラリでだいたい足ります。最後に単体バイナリが残ります。配布のことを考えた瞬間に、仮想環境や依存関係の話を始めなくていいのはやはり楽です。
私はGoを現代のC言語みたいなものだと思っています。ハードウェアのすぐ上に張り付いている感じはCほど濃くありませんが、OSの手触りに近いところを素直に触れます。ファイル、ソケット、標準入力、プロセス。そのあたりを変に飾らず扱えるのがいいです。しかも書式を巡る宗教戦争まで薄いです。道具を書く言語としては、かなり気楽です。
自分のPCのソフトウェアくらい、もっと自由に触っていいはずです。ログを読む。保存先を変える。スクレイピングする。小さな補助ツールを書く。そういう行為にいちいち遠慮する必要はありません。自分で買った机の引き出しを開けるのに許可はいらないのと同じです。
大げさな自動化はいりません。朝に一回叩くだけのCLIで十分なことは多いです。むしろその程度の道具のほうが、半年後もまだ生きています。少なくとも私は、今日もそのCLIでダウンロードフォルダを一回見てから作業を始めました。