Zsh Hooks を活用して uv venv の仮想環境を自動有効化する方法
本記事では、uv(パッケージマネージャー)のコマンド uv venv
を実行した際に、デフォルト仮想環境を自動でアクティベートする仕組みについて紹介します。Zsh のフック機能である preexec
と precmd
を利用し、add-zsh-hook
を活用したシンプルな実装例を解説します。
背景
日常的に Python の仮想環境を使っていると、仮想環境の有効化作業が面倒になることがあります。特に、uv を使って環境を管理している場合、「uv venv」コマンド実行時に対応する仮想環境を自動的にアクティベートできれば、作業効率が向上します。
コードの概要
以下のコードは、以下の点を実現しています:
-
フック関数の登録
add-zsh-hook
を使ってpreexec
とprecmd
フックに関数を登録しています。 -
コマンドの解析
コマンドライン全体をシェルの単語分割ルールに基づき配列に変換し、厳密に「uv venv」または「uv venv <venv_path>」に一致する場合にのみ処理を実行します。 -
仮想環境の自動有効化
指定された仮想環境(またはデフォルトの.venv
)が存在する場合、そのactivate
スクリプトを自動的に読み込みます。
実装例
以下は、実際に .zshrc
に追加するコードです。最初に autoload -Uz add-zsh-hook
を記述することで、add-zsh-hook
が確実に利用可能となります。
# .zshrc に追加
autoload -Uz add-zsh-hook
# 最後のコマンドを配列として保持するグローバル変数
LAST_COMMAND=()
# preexec フックで実行する関数
uvvenv_preexec() {
# シェルの単語分割(引用符も考慮)を行う
LAST_COMMAND=("${(z)1}")
}
# precmd フックで実行する関数
uvvenv_precmd() {
# コマンドが「uv venv」または「uv venv <venv_path>」の形であるかチェック
if (( ${#LAST_COMMAND[@]} == 2 || ${#LAST_COMMAND[@]} == 3 )); then
if [[ ${LAST_COMMAND[1]} == "uv" && ${LAST_COMMAND[2]} == "venv" ]]; then
# 3番目の要素があればそれを、なければデフォルトの .venv を使用
local venv_path=${LAST_COMMAND[3]:-.venv}
if [[ -d "$venv_path" && -f "$venv_path/bin/activate" ]]; then
echo "Activating virtual environment: $venv_path"
source "$venv_path/bin/activate"
else
echo "Warning: Virtual environment $venv_path not found"
fi
fi
fi
# 次回の実行のためにコマンド変数をクリア
LAST_COMMAND=()
}
# add-zsh-hook を使って各フックに関数を登録
add-zsh-hook preexec uvvenv_preexec
add-zsh-hook precmd uvvenv_precmd
詳細な解説
-
autoload の利用
autoload -Uz add-zsh-hook
は、add-zsh-hook 関数が未ロードの場合に備えて、必ずロードするための記述です。これにより、フックの登録がエラーなく行えます。 -
LAST_COMMAND の配列化
uvvenv_preexec
関数では、"${(z)1}"
を利用して入力されたコマンド文字列を配列に変換しています。これにより、引用符で囲まれた部分も正しく認識でき、正確なコマンドの解析が可能になります。 -
厳密なコマンドチェック
uvvenv_precmd
関数内で、配列の要素数が 2 または 3 であること、かつ先頭の2要素がそれぞれuv
とvenv
であることを確認しています。これにより、余計な引数が付与された場合や意図しないコマンド実行時には動作しないようにしています。 -
仮想環境の検出と有効化
指定されたパス(またはデフォルトの.venv
)にディレクトリとbin/activate
ファイルが存在するかを確認し、存在する場合は自動的に仮想環境を有効化します。もし存在しない場合は警告を表示します。 -
フックの登録
add-zsh-hook
を利用して、先ほど定義したuvvenv_preexec
とuvvenv_precmd
関数をそれぞれのフックに登録しています。これにより、シェル実行時に自動的にこれらの関数が呼ばれる仕組みになっています。
その他の記事紹介
これ以外にも以下のようなPythonの開発に役立つシェルスクリプトを紹介しています。
Discussion