zshの初期設定がダサすぎたので自分好みにカスタムをしていく。
2024-12-07
azblob://2024/12/02/eyecatch/2024-12-07-zshprompt-000_2.png

本記事はFIXER Advent Calendar 2024( FIXER Advent Calendar 2024 ~ ルーキー編 〜)12月7日の記事です。

みなさん、こんにちは!

突然ですが、コマンドシェルの表示内容ってこだわっていますか?

僕はデフォルトは味気ないな(むしろシンプル過ぎてダサいかも...?) と思っちゃうので、カスタマイズできるものはついつい自分好みにカスタマイズしちゃいます。

今日は、開発者ならほぼ毎日目にするコマンドシェルを自分好みにカスタマイズしたときの記録をシェアしたいと思います!

今回カスタマイズしていくのは タイトルにもある通り「Z Shell」です。

コマンドシェルにはbashとか色々と種類がありますが、僕は高専時代から使っているZ Shellの方が使い勝手が良いのでこちらを使用します。

また、本ブログでは表示内容をメインでカスタマイズしていきますので、これを参考にカスタマイズをしてみる!という方は適宜自分にあったものに書き替えてカスタマイズしてみてください!

使用環境

このブログの執筆に使用した環境は以下の通りです。

  • OS : Windows11
    • WSL2でインストールしたUbuntu 22.04.4 LTS
  • フォント : Cascadia Code PL

設定ファイルについて

zshには設定ファイルがあり、 基本は 「~/.zshrc」に保存されています。

初期段階では大体の方が以下の通りになってるのではないでしょうか

setopt histignorealldups sharehistory
# Use emacs keybindings even if our EDITOR is set to vi
bindkey -e
# Keep 1000 lines of history within the shell and save it to ~/.zsh_history:
HISTSIZE=1000
SAVEHIST=1000
HISTFILE=~/.zsh_history
# Use modern completion system
autoload -Uz compinit
compinit
zstyle ':completion:*' auto-description 'specify: %d'
zstyle ':completion:*' completer _expand _complete _correct _approximate
zstyle ':completion:*' format 'Completing %d'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' menu select=2
eval "$(dircolors -b)"
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
zstyle ':completion:*' list-colors ''
zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s
zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*'
zstyle ':completion:*' menu select=long
zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s
zstyle ':completion:*' use-compctl false
zstyle ':completion:*' verbose true
zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'

ここは初期設定のままで、このファイルにいろいろ設定を追加して見た目を改造していきましょう。

さっそく改変開始!

まずはデフォルトのプロンプトを見てみましょう。

かなり寂しいですね。ここから使いたくなるようなプロンプトを目指します。

(本ブログではコマンドを打って設定を反映していますが、実際に行う場合は同様のコマンドを ~/.zshrc の一番下から順に書き込んで source ~/.zshrc コマンドを実行してください。)

zshでは  RPROMPT と PROMPT という変数が使用されています。

PROMPT  : 左側に表示する内容

RPROMPT : 右側に表示する内容

「え?右側もあるの?プロンプトって左側だけあれば十分じゃん。」って思った方も多いはず。実際僕もそうでした。

ですが、ここに情報を出すことも可能なので、ここを変えるだけでかなり使い勝手が変わってきます。(詳しくは下の方でカスタマイズしていきます)

試しに RPROMPTに Test String を代入した結果が以下の通りです。

どうでしょうか 右側に Test Stringと表示されました。これでは一見、1行当たりの入力スペースが少なくなって不便じゃん!と思いがちですが、入力欄がRPROMPTにぶつかると勝手に表示をOFFにしてくれます。

さらに setopt transient_rprompt と入れると画像の様に最新の行だけにRPROMPT変数の内容が表示されます (便利)

これだけでかなり自分好みにカスタマイズすることが出来ますね。

さて、以下にPROMPT変数やRPROMPT変数に入れると便利なものを紹介します!

一般的なプロンプトシーケンス

  • %d または %/: カレントディレクトリのフルパスを表示します。
  • %~: ホームディレクトリを ~ として表示する、カレントディレクトリのパスを表示します。
  • %h: コマンド履歴のイベント番号を表示します。
  • %H: ホスト名を表示します。
  • %m: ホスト名を表示しますが、ドメイン部分は省略されます。
  • %M: フルホスト名を表示します(ドメイン部分を含む)。
  • %n: 現在のユーザー名を表示します。
  • %t または %@: 12時間形式で現在の時刻を表示します。
  • %T: 24時間形式で現在の時刻を表示します。
  • %*: 現在の時刻を24時間形式で、秒まで表示します。
  • %j: 現在のジョブ数を表示します。
  • %l: 現在のttyの端末名を表示します。
  • %N: 現在実行中のスクリプト名を表示します。

ステータス関連

  • %?: 前回実行したコマンドの終了ステータスを表示します。
  • %#: プロンプト文字を表示します。通常ユーザーでは %、スーパーユーザーでは # になります。

カスタマイズされた情報

  • %L: シェルレベル(サブシェルの深さ)を表示します。
  • %v: zshのバージョンを表示します。

色とスタイル

  • %F{色}: 文字色を指定します(例:%F{red},カラーコードも指定できます)。
  • %K{色}: 背景色を指定します(例:%K{blue},カラーコードも指定できます)。
  • %f: 文字色をデフォルトに戻します。
  • %k: 背景色をデフォルトに戻します。
  • %B%b: 太字を開始/終了します。
  • %U%u: 下線を開始/終了します。

↑ちなみにこれらは GaiXerを使って出力しました。(生成AIの時代ですからね)

左側のプロンプトのカスタマイズ

どうせならカラフルにしてみたいので、前章で出てきた {色とスタイル}を使って自分好みにカスタマイズしていきましょう。

背景色が %K{} で 文字色が%F{} なので...

PROMPT="%K{cyan}%F{black}12月って寒いですね%f%k"

とすると...(ちゃんと背景色と文字色は最後に戻して上げましょう)

おお、変わってくれましたね。

では少し複雑にして...

# 区切りに ▶ と ◀ を使うため、環境変数を設定 
export ARROW_RIGHT=$'\ue0b0'
export ARROW_LEFT=$'\ue0b2'
PROMPT="%K{cyan}%F{white} お昼は13時から! %K{#ff7777}%F{cyan}${ARROW_RIGHT} %F{black}%~ %k%F{#ff7777}%k${ARROW_RIGHT}%f"

とすると...

かなり良くなったのではないでしょうか?

では続いて右側のプロンプトを改造してみましょう

右側のプロンプトのカスタマイズ

ここには人それぞれ表示させるものが変わってきますが、gitの情報を今回は表示したいと思います。

そこで、gitの情報を持ってくるために vcs_info というものを用います。

こちらについては、vcs_info のサンプル (zsh/Misc/vcs_info-examples at master · zsh-users/zsh)を参考にしていただければと思います。

autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git # gitの情報を持ってこれるようにする
zstyle ':vcs_info:git:*' check-for-changes true # gitリポジトリ内において変更をチェックする
zstyle ':vcs_info:*' actionformats '[%b|%a]'
# ↑アクションフォーマットの設定 ([ブランチ名 | 何をしているか(リベース等)]) で表示するように設定
zstyle ':vcs_info:git:*' stagedstr "%K{white}%F{yellow}"
# ↑ステージされたファイルがある場合の書式設定 (白背景の黄色文字) %cでこれを呼び出せる
zstyle ':vcs_info:git:*' unstagedstr "%K{white}%F{red}"
# ↑ステージされたファイルがない場合の書式設定 (白背景の赤文字) %uでこれを呼び出せる
zstyle ':vcs_info:*' formats "${ARROW_LEFT}%F{green}%K{white}%c%u[%b]%f" # デフォルトの文字列の設定
vcs_info #実際に情報をGETする
RPROMPT="${vcs_info_msg_0_}" # vcs_info_msg_0_ 変数に↑で設定したフォーマットが入っているので使用

こちらを設定ファイルに書き込んでsource ~/.zshrc をするだけで右側のプロンプトにgitの情報が出ますが、ディレクトリ移動をするたびに変化などはしてくれません。

せっかくgitの情報を取得できるようにしたのにRPROMPTの情報が変わらないのでは作った意味がありません... そこで、何かのコマンドを実行する度に最新の情報を持ってきてRPROMPTに代入するような仕組みが必要です。

そこで、プロンプトを表示する前に登録されている関数を毎回実行してくれる便利な変数、precmd_functionsに毎回これを実行するように登録をします。 

これなら上記の「何かのコマンドを実行する度に最新の情報を持ってきてRPROMPTに代入するような仕組み」が実現できます。

関数の作成

せっかくなので、情報をアップデートする傍ら、git初心者がやりがちな developで作業をしてしまう問題に対して警告を出してみましょう。

まずはザックリとした構成から考えます。

  • ブランチ名を取得
    • ブランチ名がdevelopかどうか?
  • 編集したファイルがないか?
    • あったら警告を出す
  • 最後にRPROMPTの情報を最新に更新

といった流れになるので...これを生成AIに作っていただきましょう。

結構簡単ですね。これを使用してRPROMPTをカスタマイズしてみましょう。

ではこの関数を毎回実行するようにprecmd_functionsに追加します。

# 既にcheck_develop_branch関数が登録されている場合は削除
precmd_functions=(${precmd_functions[@]/"check_develop_branch"})
# プロンプト表示前にcheck_develop_branch関数を実行
precmd_functions+=(check_develop_branch)

さて、これで右側のプロンプトのカスタマイズが終わったので設定を反映してgitリポジトリのディレクトリに移動すると...?

右側に[master]と出ているので反映されていますね。では実際にdevelopブランチで作業してcommitした時などの挙動も確認してみましょう。

問題なさそうですね。これでdevelopで作業して冷や汗が出ることは格段に減りました。

エイリアスの登録

最後によく使うコマンドに対してエイリアスを登録して呼び出しやすくしてみます!

使い方はとっても簡単で

alias [登録する名前]="[実際のコマンド]"

で登録ができます。(=の左右はスペース入れたら動かないので注意...)

例えばls コマンドを打ってるときになりがちな sllsとして扱いたいとなった場合は

alias sl="ls"

で解決です。 

実際に上記内容を設定ファイルに書き込んで反映したら...

しっかりslコマンドでも反映されましたね。

長いコマンドなどもどんどんエイリアスに登録して作業時間短縮もしちゃいましょう。

最後に

本ブログでは簡単ではありますがコマンドシェルの表示内容等を改変してみました。

最初の頃のプロンプトとカスタマイズ後のプロンプトを見比べたのが以下になります。

どうでしょうか?最初に比べると少しは使いたくなるような表示になったかな、と思います。

他にも「Tabで補完する候補をハイライトする」などなどたくさんの設定がありますので気になる方は是非調べてカスタマイズしてみてください。

このブログを通して少しでもコマンドシェルのカスタマイズに興味を持って頂けましたら幸いです。

付録 (本ブログでカスタマイズした設定ファイルの最終版)

setopt histignorealldups sharehistory
# Use emacs keybindings even if our EDITOR is set to vi
bindkey -e
# Keep 1000 lines of history within the shell and save it to ~/.zsh_history:
HISTSIZE=1000
SAVEHIST=1000
HISTFILE=~/.zsh_history
# Use modern completion system
autoload -Uz compinit
compinit
zstyle ':completion:*' auto-description 'specify: %d'
zstyle ':completion:*' completer _expand _complete _correct _approximate
zstyle ':completion:*' format 'Completing %d'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' menu select=2
eval "$(dircolors -b)"
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
zstyle ':completion:*' list-colors ''
zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s
zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*'
zstyle ':completion:*' menu select=long
zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s
zstyle ':completion:*' use-compctl false
zstyle ':completion:*' verbose true
zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'
# ↑改変していない部分 改変した部分↓
# 区切りに ▶ と ◀ を使うため、環境変数を設定 
export ARROW_RIGHT=$'\ue0b0'
export ARROW_LEFT=$'\ue0b2'
PROMPT="%K{cyan}%F{white} お昼は13時から! %K{#ff7777}%F{cyan}${ARROW_RIGHT} %F{black}%~ %k%F{#ff7777}%k${ARROW_RIGHT}%f"
# 最新の行だけRPROMPTを表示
setopt transient_rprompt
# Created by newuser for 5.8.1
autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git # gitの情報を持ってこれるようにする
zstyle ':vcs_info:git:*' check-for-changes true # gitリポジトリ内において変更をチェックする
zstyle ':vcs_info:*' actionformats '[%b|%a]'
# ↑アクションフォーマットの設定 ([ブランチ名 | 何をしているか(リベース等)]) で表示するように設定
zstyle ':vcs_info:git:*' stagedstr "%K{white}%F{yellow}"
# ↑ステージされたファイルがある場合の書式設定 (白背景の黄色文字) %cでこれを呼び出せる
zstyle ':vcs_info:git:*' unstagedstr "%K{white}%F{red}"
# ↑ステージされたファイルがない場合の書式設定 (白背景の赤文字) %uでこれを呼び出せる
zstyle ':vcs_info:*' formats "${ARROW_LEFT}%F{green}%K{white}%c%u[%b]%f" # デフォルトの文字列の設定
vcs_info
# developブランチでファイルがmodifiedになった場合に警告メッセージを表示する関数
function check_develop_branch() {
    # 現在のブランチを取得
    branch=$(git symbolic-ref --short HEAD 2>/dev/null)
    # ブランチがdevelopであるかを確認
    if [ "$branch" = "develop" ]; then
        # modifiedファイルの数を取得
        modified_files=$(git status --porcelain | grep "^ M" | wc -l)
        # modifiedファイルが存在する場合は警告メッセージを表示
        if [ "$modified_files" -gt 0 ]; then
            echo -e "\033[48;5;11;38;5;9;1mdevelopで作業しています。ブランチを変更してください。\033[0m"
        fi
    fi
    vcs_info
    RPROMPT="${vcs_info_msg_0_}" # vcs_info_msg_0_ 変数に↑で設定したフォーマットが入っているので使用
}
# 既に登録されている場合は削除
precmd_functions=(${precmd_functions[@]/"check_develop_branch"})
# プロンプト表示前にcheck_develop_branch関数を実行
precmd_functions+=(check_develop_branch)
RPROMPT="${vcs_info_msg_0_}" # vcs_info_msg_0_ 変数に↑で設定したフォーマットが入っているので使用
# エイリアス
alias sl="ls"