add-zsh-hookでZsh Hookを登録する方法|precmd・preexecなど発動タイミングと実例

add-zsh-hook は、プロンプト表示の直前(precmd)やコマンド実行の直前(preexec)など、決まったタイミングで自動的に関数を呼び出す「Zsh Hook」を登録するためのコマンドです。zsh標準の関数ライブラリに含まれ、autoload -Uz add-zsh-hook で読み込んでから add-zsh-hook <フック名> <関数名> の形で使います。扱えるフックは precmd・preexec・chpwd・periodic・zshaddhistory・zshexit・zsh_directory_name の7種類です。この記事では各フックの発動タイミングと引数、登録・解除の手順、複数登録時の実行順序、そしてGitブランチ表示やコマンドログといった実例までをコード付きで整理します。

まとめ:add-zsh-hookとZsh Hookの要点

  • 読み込みは1回だけautoload -Uz add-zsh-hook~/.zshrc に書いてから使う。
  • 基本構文add-zsh-hook precmd 関数名。解除は -d、登録済み一覧は -L
  • 扱えるフックは7種:precmd / preexec / chpwd / periodic / zshaddhistory / zshexit / zsh_directory_name。用途で使い分ける。
  • 複数登録は登録順に実行:戻り値で中断されず、並べた順にすべて呼ばれる。
  • 配列直接追記より add-zsh-hook 推奨:重複登録を防ぎ、関数の autoload まで面倒を見てくれる。
  • precmd は毎プロンプトで走る:重い処理を入れると入力のたびに待たされるため、計測して軽量化する。

Zsh Hookとは:発動タイミングで自動実行される特殊関数

Zsh Hookは、シェルが特定のイベントに到達したときに自動で呼び出す関数の総称です。たとえば precmd という名前の関数を定義しておくと、zshはプロンプトを表示する直前に毎回その関数を実行します。プロンプトへの情報表示、コマンドの実行ログ、ディレクトリ移動時の処理などを、ユーザーが明示的に呼び出さなくても差し込めるのが特徴です。

「_functions」配列で複数の関数を同じフックに束ねる仕組み

zshの各フックには、フック名に _functions を付けた同名の配列(例:precmd_functionspreexec_functions)を定義できます。この配列の各要素は実行すべき関数名として扱われ、基本のフック関数と同じコンテキスト・同じ引数・同じ $? の初期値で、配列に並んだ順に実行されます。add-zsh-hook は内部でこの配列に関数名を追加しているだけで、仕組み自体は zsh 本体の機能です。

Git HookやシェルのtrapとZsh Hookの違い

同じ「フック」でも、Gitのコミット時に走る Git Hook(.git/hooks 配下のスクリプト)や、シグナルを捕捉する trap とは別物です。Zsh Hookはあくまで対話シェルの操作イベント(プロンプト表示・コマンド実行・ディレクトリ移動など)に反応する仕組みで、リポジトリ操作やシグナルではなく日々のシェル操作に紐づきます。Gitの操作自体を確認したい場合はGitコマンド一覧|用途別早見表とよく使う基本コマンドの使い方を解説を参照してください。

Zsh Hookの種類と発動タイミング一覧

add-zsh-hook が受け付けるフックは、ソース内の hooktypes に定義された次の7種類です。それぞれ発動タイミングと渡される引数が異なります。

フック 発動タイミング 主な用途
precmd 各プロンプト表示の直前 プロンプト更新・情報表示
preexec コマンドを読み込み実行する直前 実行ログ・所要時間の計測
chpwd カレントディレクトリの変更時 移動先の情報表示
periodic $PERIOD 秒ごと(プロンプト前) 定期的な更新処理
zshaddhistory 履歴行を登録する直前 履歴に残す/残さないの制御
zshexit シェルが正常終了する直前 後始末・クリーンアップ
zsh_directory_name 動的ディレクトリ名の解決時 名前付きディレクトリの変換

precmd・preexec:プロンプトとコマンド実行の前後

precmd は引数を取らず、プロンプトを表示する直前に呼ばれます。単にコマンドラインが再描画されただけでは再実行されない点が実装上のポイントです。preexec は3つの引数を受け取ります。第1引数は履歴が有効なときにユーザーが入力した文字列(無効時は空)、第2引数は1行・サイズ制限付きに整形したコマンド、第3引数は実際に実行される完全なテキストです。第1引数を使えば、入力したコマンドそのものをログに残せます。

chpwd・periodic:ディレクトリ移動と定期実行

chpwdcd などでカレントディレクトリが変わるたびに呼ばれ、移動先の $PWD や直前の $OLDPWD を参照して表示を切り替える用途に向きます。periodicPERIOD パラメータに秒数を設定したときだけ有効で、その秒数ごとにプロンプト表示前に実行されます。間隔は配列内のすべての periodic 関数に共通で1つだけ適用されます。

zshaddhistory・zshexit:履歴フィルタと終了処理

zshaddhistory は、対話的に読み込んだ履歴行が実行される前に呼ばれ、引数として完全な履歴行が渡されます。戻り値で履歴の保存可否を制御でき、0を返せば通常どおり保存、2以外の0以外(例:1)を返すとその行は履歴に保存されません。2を返した場合は内部履歴には残りますがファイルには書き込まれません。zshexit はメインのシェルが正常終了する直前に呼ばれ、一時ファイルの削除やログのフラッシュなど後始末に使います。

add-zsh-hookでフックを登録・解除する手順

add-zsh-hook は zsh 標準の関数として同梱されており、使う前に autoload で読み込みます。

読み込みと基本構文

# ~/.zshrc に記述
autoload -Uz add-zsh-hook

# プロンプト表示前に時刻を出す関数を定義
show_time() {
  print -P "%F{green}%D{%H:%M:%S}%f"
}

# precmd フックに登録
add-zsh-hook precmd show_time

autoload -Uz-U はエイリアス展開の抑制、-z は zsh スタイルでの読み込みを指定するオプションで、関数を安全に自動ロードするための定番の組み合わせです。登録の書式は add-zsh-hook <フック名> <関数名> の1行だけです。

-dで解除・-Lで一覧表示するオプション

add-zsh-hook -d precmd show_time   # 指定した関数をフックから外す
add-zsh-hook -D precmd 'show_*'    # パターンに一致する関数をまとめて外す
add-zsh-hook -L                    # 登録済みフックの中身を一覧表示

-d は関数を1つ解除し、フック配列が空になればフック変数自体も削除します。-D はパターン指定でまとめて解除、-L は現在の登録状況の確認に使います。関数名を渡すと add-zsh-hook が内部で autoload も行うため、関数をファイルに分けて fpath に置いておけば、定義済みでなくても登録できます。

_functions配列に直接追記する方法との違い

precmd_functions+=(show_time) のように配列へ直接追記しても同じ効果は得られますが、同じ関数を二重に書くと二重登録になり、プロンプトのたびに2回実行されてしまいますadd-zsh-hook は登録済みかを確認したうえで追加し、必要なら関数の autoload まで引き受けます。設定ファイルを何度も source し直す運用では、重複を避けられる add-zsh-hook 経由の登録が安全です。

複数フックの実行順序と管理

1つのフックに複数の関数を登録した場合、それらは precmd_functions などの配列に並んだ順、つまり登録した順に実行されます。各関数は同じ $? の初期値で呼ばれ、いずれかが0以外を返しても後続の関数はそのまま実行されます(配列内の関数は戻り値で中断されません)。順序が重要な処理(先に情報を集めてから表示する等)は、登録する順番そのもので制御します。現在の並びは add-zsh-hook -Lprint -l $precmd_functions で確認でき、意図しない順序や多重登録の切り分けに役立ちます。

Zsh Hookの実用例:プロンプト・履歴・自動化

chpwd+precmdでGitブランチをプロンプトに表示する

autoload -Uz add-zsh-hook vcs_info
zstyle ':vcs_info:git:*' formats '%b'

_load_branch() { vcs_info }
add-zsh-hook precmd _load_branch

setopt PROMPT_SUBST
RPROMPT='${vcs_info_msg_0_}'

zsh同梱の vcs_info を precmd で毎回呼び、現在のブランチ名を右プロンプトに表示します。ディレクトリを跨いでリポジトリが変わる場合は chpwd にも同じ関数を登録すると、移動直後から表示が更新されます。プロンプト全体を作り込むならStarshipとは?Rust製シェルプロンプト 導入・設定・カスタマイズガイドのような専用ツールと組み合わせる選択肢もあります。

preexecでコマンドの実行ログを残す

log_command() {
  print "[$(date '+%F %T')] $1" >> ~/.zsh_cmdlog
}
add-zsh-hook preexec log_command

preexec の第1引数には入力したコマンドがそのまま入るため、実行の直前にタイムスタンプ付きでファイルへ追記できます。所要時間を測りたい場合は preexec で開始時刻を変数に記録し、precmd で差分を計算して表示する方法がよく使われます。

zshaddhistoryで履歴に残さないコマンドを除外する

skip_secret_history() {
  [[ $1 == *"AWS_SECRET"* ]] && return 1   # 履歴に残さない
  # return 2 なら内部履歴だけに残しファイルには書かない
  return 0
}
add-zsh-hook zshaddhistory skip_secret_history

秘匿情報を含むコマンドを履歴に残したくないケースで有効です。条件に一致したら return 1(0以外)を返して保存をスキップし、それ以外は return 0 で通常どおり保存します。誤って条件を広げると必要な履歴まで消えるため、パターンは限定的に書きます。

フックが動かないときのトラブルシューティング

登録したのに動かない:autoloadと関数名を確認する

最初に疑うべきは、autoload -Uz add-zsh-hook を書く前に add-zsh-hook を呼んでいないか、そして登録した関数名のタイプミスです。add-zsh-hook -L で対象のフックに関数が並んでいるかを確認し、並んでいなければ登録行が実行されていません。関数をファイル分割している場合は、そのディレクトリが fpath に含まれているかも確認します。ファイルやディレクトリの取り回しはLinuxのファイル操作コマンド一覧とその使い方ガイドが参考になります。

precmdの重い処理でプロンプトが遅くなる失敗パターン

precmd はプロンプトを出すたびに毎回実行されるため、ここに外部コマンドの起動やネットワークアクセスなど重い処理を入れると、コマンドを打つたびに入力が待たされます。体感が遅いときは、precmd から呼ぶ処理を time で計測し、キャッシュ化する・periodic に逃がす・そもそも precmd から外す、のいずれかで軽量に保つべきです。「便利だから」と precmd に処理を積み増すのは、対話シェルではもっとも避けたい設計です。設定ファイルは機能ごとに分割し、add-zsh-hook -L で登録内容を定期的に見直すと肥大化を防げます。

よくある質問(FAQ)

add-zsh-hookはどこで定義されていますか?

zsh本体に同梱される関数ライブラリ(Functions/Misc/add-zsh-hook)に含まれています。組み込みコマンドではなく autoload 対象の関数のため、autoload -Uz add-zsh-hook で読み込んでから使います。

precmdとpreexecの違いは何ですか?

precmd はプロンプトを表示する直前に引数なしで呼ばれ、preexec はコマンドを実行する直前に、入力したコマンド文字列を引数として受け取って呼ばれます。「表示の前」か「実行の前」かで使い分けます。

特定のコマンドを履歴に残さないようにできますか?

zshaddhistory フックを使い、対象を判定したら return 1(0以外・ただし2を除く)を返すとその行は履歴に保存されません。2を返すと内部履歴には残りますがファイルには書かれません。

precmd_functionsに直接追加するのとadd-zsh-hookは何が違いますか?

結果は同じですが、add-zsh-hook は同じ関数の二重登録を避け、関数の autoload も行います。設定を何度も読み込み直す環境では二重登録による重複実行を防げるため、add-zsh-hook 経由が安全です。

chpwd hookでは何ができますか?

カレントディレクトリが変わるたびに呼ばれるため、移動先に応じてプロンプトや環境変数を切り替えたり、ls を自動実行したり、リポジトリ情報を更新したりといった「ディレクトリ移動を起点にした自動処理」を差し込めます。

関連記事

資料請求

RELATED POSTS 関連記事