1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェル履歴を「育てる」CLIツール rcmd を作った

1
Posted at

はじめに

Ctrl+R で履歴を検索するたびに思っていたことがある。

「このコマンド、また使いたいんだけど、なんて打ったっけ。」

atuinfzfhstr も試した。どれも優秀だった。でも根本的な問題は解決しなかった。履歴は「全部」記録する。自分が必要なのは「また使いたい一部」だけ。

10,000件の履歴から1件を見つける作業を繰り返すうちに、発想が逆転した。

「検索する」じゃなくて「育てる」ツールを作ればいい。

それが rcmd です。


rcmd とは

CLI のための個人コマンド知識ベース。

覚えておきたいコマンドだけを手元に残し、{{プレースホルダー}} でテンプレート化して、タグと全文検索で呼び出す。ストレージは TOML ファイル1枚なので dotfiles で複数マシンに同期できる。

# 保存する
rcmd save "docker run --rm -it -v {{path}}:/work {{image}} bash" \
    -d "カレントディレクトリをマウントしてインタラクティブシェル" \
    -t docker -t dev

# 呼び出す
rcmd get k3f9 --set path=$PWD --set image=alpine

# そのまま実行する
rcmd run k3f9 --set path=. --set image=alpine

atuin / fzf との違い

atuin / fzf / hstr rcmd
対象 全履歴 手動で選んだコマンド
アプローチ 検索 キュレーション
テンプレート なし {{placeholder}} 置換あり
説明・タグ なし あり
ストレージ DB / バイナリ TOML(手編集可)

両方使えばいい、というのが自分のスタンス。atuin は「あのコマンドどこ行った」を救う。rcmd は「このコマンドは残しておく」を管理する。


なぜ作ったか

きっかけ:docker コマンドが壊れていた

docker の volume マウント付き interactive シェルを毎回ゼロから書いていた。--rm -it -v $(pwd):/work を何度入力したか数えたくない。

メモアプリに貼っておいたこともあった。でも貼ったまま忘れる。ノート検索よりシェルの方が速い。

既存ツールへの不満

  • alias → 引数が固定になる。汎用化しにくい
  • function.zshrc が育ちすぎる。管理が辛い
  • ノートアプリ → コンテキストスイッチが発生する
  • .sh ファイル群 → どこに置いたか忘れる

「コマンドライン内で完結して、テンプレート化できて、検索できる」ものがなかった。


主な機能

{{プレースホルダー}} 置換

コマンドにプレースホルダーを埋め込んで、呼び出し時に値を注入する。

# 保存時
rcmd save "ffmpeg -i {{input}} -vf scale={{width}}:-1 {{output}}" \
    -d "動画リサイズ" -t ffmpeg

# 呼び出し時
rcmd run a1b2 --set input=video.mp4 --set width=720 --set output=out.mp4

# --dry-run でプレビューしてから実行
rcmd run a1b2 --set input=video.mp4 --set width=720 --set output=out.mp4 --dry-run

--dry-run は地味に便利で、破壊的操作の前に展開結果を確認できる。

タグ & 全文検索

# タグで絞り込む
rcmd list -t docker

# キーワードで検索(1行出力なので fzf と組み合わせやすい)
rcmd search volume

# 詳細表示
rcmd show k3f9

出力を1行フォーマットにしたのは意図的な設計。fzf にパイプしてインタラクティブに選べる。

# fzf と組み合わせた例
rcmd search docker | fzf | awk '{print $1}' | xargs rcmd show

シェル履歴からの一括インポート

rcmd history --unique --reverse | fzf | rcmd save -d "説明を書く" -t imported

まっさらから始める必要はない。今ある履歴から「また使いたいもの」を選んで登録できる。

TOML ストレージ

~/.config/rcmd/store.toml     # macOS / Linux
%APPDATA%\rcmd\store.toml     # Windows

中身はこんな感じ:

[commands.k3f9]
command = "docker run --rm -it -v {{path}}:/work {{image}} bash"
description = "カレントディレクトリをマウントしてインタラクティブシェル"
tags = ["docker", "dev"]
created_at = "2026-06-01T12:00:00"

プレーンテキストなので手で編集できる。$RCMD_STORE 環境変数でパスを上書きすれば、dropbox や dotfiles リポジトリの任意の場所に置ける。


技術選定

Python + typer

依存は typer のみ。

typer を選んだ理由は3つ:

  1. 型アノテーションだけでCLIが生えるargparse のボイラープレートを書かなくていい
  2. --help が自動で綺麗 — ドキュメントを別で書かなくていい
  3. uv と相性がいいuv sync && uv run rcmd --help で即起動
import typer

app = typer.Typer()

@app.command()
def save(
    command: str,
    description: str = typer.Option("", "-d", "--description"),
    tags: list[str] = typer.Option([], "-t", "--tag"),
):
    """コマンドを保存する"""
    ...

型ヒントを書くだけでオプション・ヘルプ・バリデーションが揃う。CLIツールを Python で作るなら今は typer が最短距離だと思う。

ストレージに TOML を選んだ理由

SQLite も検討した。でも TOML にした。

SQLite の問題:

  • バイナリなので git diff が読めない
  • 手編集できない
  • dotfiles に入れても差分が追いにくい

TOML の問題:

  • 大量データには向かない(個人用途なので問題なし)
  • インデックスがない(全文検索は Python 側で処理)

個人コマンド集なら数百件が上限。SQLite のメリットが薄く、TOML の可読性・可搬性の方が価値が高いと判断した。

ID の生成

各コマンドには k3f9 のような短いランダムIDを付与している。

import secrets
import string

def generate_id(length: int = 4) -> str:
    chars = string.ascii_lowercase + string.digits
    return ''.join(secrets.choice(chars) for _ in range(length))

UUID は長すぎて入力しにくい。4文字のランダム英数字で衝突確率は約 0.06%(1,679,616通り)。コマンド数が数百件の個人用途では十分。


インストール

git clone https://github.com/ymatsuza/rcmd.git && cd rcmd
uv sync
uv run rcmd --help

uv がない場合は astral.sh/uv から。

グローバルで使いたい場合:

# PATH が通った場所にシンボリックリンクを張る
ln -s $(pwd)/bin/rcmd ~/.local/bin/rcmd

実際の使い方(自分の場合)

週1で棚卸しする

rcmd history --unique --reverse | fzf | rcmd save を週1で走らせて、先週のコマンドから「残しておきたいもの」を登録する。

タグは用途より文脈で付ける

dockerffmpeg のようなツール名タグよりも、workhobbysetup のような文脈タグの方が後から見つけやすかった。両方付けるのが今のところ最善。

dotfiles で同期する

$RCMD_STORE=~/dotfiles/rcmd/store.toml.zshrc に書いて dotfiles リポジトリに入れている。マシンを変えても git pull で全部復元する。


今後やりたいこと

  • rcmd export でバックアップ・インポート
  • シェル補完(zsh / bash / fish)
  • rcmd run の実行ログ(いつ何を実行したかの追跡)
  • Web UI(ローカルで立ち上げてブラウザから管理)

まとめ

シェル履歴の「検索」ではなく「キュレーション」を目的にしたツールを作った。

作ってから3ヶ月、自分の一番使うCLIツールのひとつになった。docker run を毎回ゼロから打つストレスがなくなった。

フィードバック・PR・star、歓迎しています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?