😽

記憶喪失のターミナルを天才に育てる魔法の呪文

に公開

ターミナルは記憶喪失?

「さーて、昨日やってたあのプロジェクトの続きをやるか!」

新しいターミナルを開くと、いつも出迎えてくれるのはホームディレクトリ (~/)。
そこから cd path/to/my/super/awesome-project/src/and/so/on のような長い道のりを、毎日毎日、律儀にタイプしていませんか?

まるでターミナルが毎朝きっかり記憶喪失になっているかのようです。

「昨日どこまで進めたか、覚えていてくれたらいいのに…」

そんなあなたのための、たった数行の魔法の呪文(スクリプト)をご紹介します。

記憶力を取り戻す呪文(初級編)

まずは小手調べ。この呪文をあなたの ~/.bashrc~/.zshrc の末尾に貼り付けてみてください。ターミナルが最後にいた場所を健気に覚えてくれるようになります。

# 記憶喪失のターミナルに「最後の場所」を思い出させる呪文
# ※VSCodeの内蔵ターミナルでは魔法が暴発しないよう除外する紳士協定つき
if [ -z "$VSCODE_INJECTION" ] && [ "$TERM_PROGRAM" != "vscode" ]; then
    # コマンド実行直前に、現在の場所をこっそりメモさせる
    PROMPT_COMMAND='pwd > ~/.last_dir'

    # ターミナル起動時、前回のメモを読んでその場所にワープする
    if [ -f ~/.last_dir ]; then
        cd "$(cat ~/.last_dir)"
    fi
fi

天才に育てる呪文(上級編):記憶の迷宮へ、いざ出発

これを ~/.bashrc~/.zshrc に唱えれば、ターミナルを開くたびに、過去の冒険の軌跡(ディレクトリ履歴)をリストアップし、どこへでも一瞬でワープできるようになります。

さらに! 今回は特別に、複数の場所に同時にワープできる「複数選択機能」を追加しました!
まるで忍者のように、複数の隠れ家を使いこなしましょう!

# 履歴ファイルの設定
DIR_HISTORY_FILE=~/.dir_history
# 記憶するディレクトリの最大数
MAX_HISTORY_SIZE=10

if [ -z "$VSCODE_INJECTION" ] && [ "$TERM_PROGRAM" != "vscode" ]; then
    # コマンド実行直前に実行される関数を定義
    _save_current_dir() {
        local current_dir="$(pwd)"
        local history=()
        local unique_history=""

        # 履歴ファイルを読み込み、配列に格納
        if [ -f "$DIR_HISTORY_FILE" ]; then
            IFS=$'\n' read -r -d '' -a history < "$DIR_HISTORY_FILE"
        fi

        # 配列の先頭に現在のディレクトリを追加
        history=("$current_dir" "${history[@]}")

        # 重複を除去し、最新のMAX_HISTORY_SIZE件に絞る
        # (最新のディレクトリが先頭に来るため、この順で処理)
        declare -A seen
        for dir in "${history[@]}"; do
            if [ -z "${seen[$dir]}" ]; then
                unique_history="$unique_history$dir\n"
                seen["$dir"]=1
            fi
        done

        # ファイルに書き戻す(最新MAX_HISTORY_SIZE件のみ)
        echo -e "$unique_history" | head -n $MAX_HISTORY_SIZE > "$DIR_HISTORY_FILE"
    }

    # PROMPT_COMMANDに記憶関数を登録
    PROMPT_COMMAND='_save_current_dir'

    # ターミナル起動時の処理(選択・移動)
    if [ -f "$DIR_HISTORY_FILE" ]; then
        echo -e "\n**🚀 以前のディレクトリ履歴:**"

        # 履歴ファイルの内容を配列に読み込む
        # IFS=$'\n'を設定し、改行でのみ区切るようにする
        # read -d '' を使用して、ヌル文字まで(またはファイル全体)を読み込む
        IFS=$'\n' read -r -d '' -a DIR_OPTIONS < "$DIR_HISTORY_FILE"

        # 最後の選択肢(現在の場所にとどまる)を追加
        DIR_OPTIONS+=("現在の場所にとどまる")

        # selectに配列を渡す
        select dir in "${DIR_OPTIONS[@]}"; do
            if [ "$dir" == "現在の場所にとどまる" ] || [ -z "$dir" ]; then
                echo "移動しませんでした。"
                break
            elif [ -d "$dir" ]; then
                # 選択されたディレクトリへ移動
                cd "$dir"
                echo "➡️ **$dir** へ移動しました。"
                break
            else
                # このエラーメッセージは通常出なくなるはずです
                echo "無効な選択です。再度選択してください。"
            fi
        done
        echo "" # 改行を追加してプロンプトを見やすくする
    fi
fi

パフォーマンスも考慮したさらなる進化した呪文

「毎回勝手に移動されるのはちょっと...」
「履歴が増えすぎてディスクが重くなるのは嫌だ!」

そんなわがままな(もとい、こだわり派の)あなたには、こちらの上級者向け呪文を授けましょう。

この呪文は以下の点で進化しています:

  1. ディスクへの優しさ (I/O最適化): 履歴の読み書きを最小限に抑え、SSDの寿命を延ばします(たぶん)。
  2. 整理整頓 (重複排除): 同じディレクトリが履歴に何度も登場するのを防ぎます。スマートですね。
  3. 自由意志の尊重 (jコマンド): ターミナル起動時に勝手に移動しません。移動したい時は j と唱えるだけ。
# VSCodeのターミナルでない場合のみ実行
# 履歴ファイルの設定
DIR_HISTORY_FILE=~/.dir_history
MAX_HISTORY_SIZE=10

if [ -z "$VSCODE_INJECTION" ] && [ "$TERM_PROGRAM" != "vscode" ]; then
    _save_current_dir_optimized() {
        local current_dir="$(pwd)"
        local history=()
        local unique_history=""
        local count=0

        # 1. 履歴ファイルを読み込み
        if [ -f "$DIR_HISTORY_FILE" ]; then
            # 配列に読み込む(改行区切り)
            IFS=$'\n' read -r -d '' -a history < "$DIR_HISTORY_FILE"
        fi

        # 2. 最新のディレクトリを先頭に追加し、重複を除去しながら配列を作成
        declare -A seen
        for dir in "$current_dir" "${history[@]}"; do
            # 最大数に達したら終了
            if [ "$count" -ge "$MAX_HISTORY_SIZE" ]; then
                break
            fi

            if [ -z "${seen[$dir]}" ]; then
                unique_history="$unique_history$dir\n"
                seen["$dir"]=1
                count=$((count + 1))
            fi
        done

        # 3. ファイルに書き戻す (1回のI/O操作に集約)
        echo -e "$unique_history" > "$DIR_HISTORY_FILE"
    }

    # PROMPT_COMMANDに軽量化された関数を登録
    PROMPT_COMMAND='_save_current_dir_optimized'
fi

# `j` コマンドでディレクトリ履歴を選択できるようにする関数 (上記スクリプトの後に追加)
j() {
    if [ -f "$DIR_HISTORY_FILE" ]; then
        echo -e "\n**🚀 ディレクトリ履歴:**"
        IFS=$'\n' read -r -d '' -a DIR_OPTIONS < "$DIR_HISTORY_FILE"
        DIR_OPTIONS+=("現在の場所にとどまる")

        # fzf がインストールされていれば fzf を使用
        if type fzf >/dev/null 2>&1; then
            local selected_dir
            selected_dir=$(printf '%s\n' "${DIR_OPTIONS[@]}" | fzf --prompt="Select Directory: " --height=~40% --layout=reverse --border)

            if [ -n "$selected_dir" ] && [ "$selected_dir" != "現在の場所にとどまる" ]; then
                cd "$selected_dir"
                echo "➡️ **$selected_dir** へ移動しました。"
            else
                echo "移動しませんでした。"
            fi
        else
            # fzf がなければ select を使用
            select dir in "${DIR_OPTIONS[@]}"; do
                if [ "$dir" == "現在の場所にとどまる" ] || [ -z "$dir" ]; then
                    echo "移動しませんでした。"
                    break
                elif [ -d "$dir" ]; then
                    cd "$dir"
                    echo "➡️ **$dir** へ移動しました。"
                    break
                else
                    echo "無効な選択です。再度選択してください。"
                fi
            done
        fi
        echo ""
    else
        echo "ディレクトリ履歴ファイルが見つかりません: $DIR_HISTORY_FILE"
    fi
}

使い方

  1. 上記のスクリプトを .bashrc などに追記し、source ~/.bashrc で読み込みます。
  2. ターミナルで作業します(履歴が溜まります)。
  3. 移動したくなったら、j と打ってエンター!
$ j

**🚀 ディレクトリ履歴:**
1) /home/user/projects/awesome-app
2) /var/log
3) 現在の場所にとどまる
#? 

数字を選べば、その場所にワープできます。

秘密のスパイス: fzf

もしあなたの環境に fzf (fuzzy finder) がインストールされていれば、この呪文は真の力を発揮します。
j コマンドを実行すると、リッチなインタラクティブ画面で履歴を検索・選択できるようになります。
これぞ、現代の魔法使いにふさわしいツールです。

ぜひ、インストールして試してみてください。世界が変わりますよ。

Discussion