世界を動かす技術を、日本語で。

ZSHシェルの高速化

概要

  • Zshシェルの起動が遅い問題の原因分析と改善手順
  • zprofによるプロファイリング方法の紹介
  • Oh-My-Zshや補完システム、Spaceship Promptの高速化設定
  • プラグイン管理と最適な設定順序
  • Before/Afterの設定例と効果比較

Zshシェル起動遅延のプロファイリングと高速化

  • Zshシェル の起動が毎回5秒以上かかる問題

  • 長年そのまま使っていたが、なぜ遅いのか気になりプロファイリングを実施

  • zprof という組み込みプロファイラを使用

    • .zshrcの先頭に zmodload zsh/zprof を追記
    • .zshrcの末尾に zprof を追記
    • 起動時に詳細な実行時間レポートを出力
  • プロファイリング結果(例)

    • _omz_source(Oh-My-Zshの読み込み): 55.73%
    • compinit(補完システム): 30.76%
    • syntax-highlight(シンタックスハイライト): 14.63%

Oh-My-Zshの高速化

  • Oh-My-Zsh の自動更新や不要な機能を無効化

    • .zshrc先頭に以下を追加
      • DISABLE_AUTO_UPDATE="true"
      • DISABLE_MAGIC_FUNCTIONS="true"
      • DISABLE_COMPFIX="true"
  • JonLucaの調査によると、これで読み込み時間が半分程度に短縮

補完システム(compinit)の最適化

  • compinit は補完キャッシュを毎回再構築するため遅い

  • キャッシュを1日1回だけ再構築する設定に変更

    autoload -Uz compinit
    if [ "$(date +'%j')" != "$(stat -f '%Sm' -t '%j' ~/.zcompdump 2>/dev/null)" ]; then
      compinit
    else
      compinit -C
    fi
    
  • GitHub Gistなどで共有されているテクニック

Spaceship Promptの高速化

  • Spaceship Prompt は便利だが重い場合がある

  • 非同期表示や最小限のセクションのみ表示する設定

    • SPACESHIP_PROMPT_ASYNC=true
    • SPACESHIP_PROMPT_ADD_NEWLINE=true
    • SPACESHIP_CHAR_SYMBOL="⚡"
    • SPACESHIP_PROMPT_ORDER=( time user dir git line_sep char )
  • 必要な項目だけに絞ることで大幅に高速化

プラグイン管理とパフォーマンス

  • プラグイン数は最小限に絞る

  • zsh-syntax-highlighting は必ず最後に記述

    plugins=(
      git
      zsh-autosuggestions
      zsh-syntax-highlighting
    )
    
  • zsh-autosuggestionsのパフォーマンス設定

    • ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE="20"
    • ZSH_AUTOSUGGEST_USE_ASYNC=1

効果比較(Before/After)

| コンポーネント | Before | After | |-----------------------|--------|--------| | Oh-My-Zsh | 55.73% | ~20% | | 補完システム | 30.76% | ~10% | | シンタックスハイライト | 14.63% | ~8% | | 総起動時間 | ~5秒 | ~0.5秒 |

  • 体感で10倍の高速化を実現

Before/Afterの設定例

Before(一部抜粋)

export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="spaceship"
SPACESHIP_PROMPT_ASYNC=false
plugins=( git zsh-syntax-highlighting zsh-autosuggestions )
source $ZSH/oh-my-zsh.sh
# ...(他にも多数の設定)

After(最適化後)

DISABLE_AUTO_UPDATE="true"
DISABLE_MAGIC_FUNCTIONS="true"
DISABLE_COMPFIX="true"
autoload -Uz compinit
if [ "$(date +'%j')" != "$(stat -f '%Sm' -t '%j' ~/.zcompdump 2>/dev/null)" ]; then
  compinit
else
  compinit -C
fi
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="spaceship"
SPACESHIP_PROMPT_ASYNC=true
SPACESHIP_PROMPT_ADD_NEWLINE=true
SPACESHIP_CHAR_SYMBOL="⚡"
SPACESHIP_PROMPT_ORDER=( time user dir git line_sep char )
plugins=( git zsh-autosuggestions zsh-syntax-highlighting )
source $ZSH/oh-my-zsh.sh
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#663399,standout"
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE="20"
ZSH_AUTOSUGGEST_USE_ASYNC=1
# ...(他にも最適化済みの設定)

その他の選択肢と感想

  • StarshipPure promptfast-syntax-highlightingZinit などの高速化ツールも存在
  • 個人的にはZsh+Oh-My-Zsh+Spaceshipの組み合わせに満足
  • 現状のセットアップが十分速ければ無理に変更しなくてもOK
  • 好奇心で試した結果、劇的に快適なシェル環境を実現

  • 同じ悩みを持つ方の参考になれば幸い

Hackerたちの意見

2〜3年前にこの問題に気づいたんだ。ちょっと古いマシンだと、起動時間が結構長かった。俺の解決策は、OhMyZSHをいじって、必要ない部分を全部削除することだった(これを「leanZSH」って呼んでるんだけど、OMZのかなり軽いバージョンだよ)。アップストリームは追ってないし、プラグインディレクトリはたまに手動で更新してる。意外とOhMyZSHはモジュール式で、壊れにくいんだよね。 [あまり良いハックじゃないけど、これがそのリンクだよ: https://github.com/gradientwolf/leanzsh 最新のplugin/フォルダをOMZのリポジトリからコピーすれば更新できるよ。いらないプラグインやテーマも全部削除できるし、なんだかんだで動くんだ。]

https://starship.rsに切り替えた方がいいと思うよ。最初は自分でzshの設定やテーマを一から作ろうとしたけど、時間がかかって、ちょっとした機能(Pythonのバージョンやvenvとか)を実装するのが面倒だったから、結局starshipに切り替えたんだ。こっちはすごく速くて使いやすいよ。

Antidoteを使えば、必要なOhMyZshの部分だけを選んで読み込むことができるよ。 - https://github.com/getantidote/use-omz 自分の使い方はこちら: https://code.millironx.com/millironx/nix-dotfiles/src/commit...

https://github.com/romkatv/powerlevel10k?tab=readme-ov-file#...

残念ながら、実質的に開発が終了してるね。

これが答えだね。

もう何年も使ってるけど、戻るなんて考えられない。

Oh-my-zshにはクールで便利な機能がたくさんあるけど、めちゃくちゃ重くて複雑なんだよね。個人的には3〜4個の機能しか気にしてなかったから、単純に削除して、その機能だけを有効にする方法を探したんだ。それに、OMZには欲しい機能が結構なかったから、結局カスタムの部分が多かったよ。参考までに俺のzshrc: https://git.sr.ht/~whynothugo/dotfiles/tree/269248912920d25e...

絵文字のエイリアスって何?

これ、絶対パクるわ:export LESS='-RX --quit-if-one-screen'

Oh-my-zshはかなり重いよ。必要ないかもしれないね。よく使う機能はzshで直接実装できるし: https://ianyepan.github.io/posts/moving-away-from-ohmyzsh/

OMZは「サービスとしてのサプライチェーン攻撃」に分類されるべきだと思う。誰が使ってるのか信じられない。

3年前にfishに移行したけど、今まで特に違いに気づいてないよ。

あなたは賢いし、センスもいいね。

Fish派、代表!

こんな記事がいつも出てくるせいで、oh-my-zshはzshの評判を seriously 傷つけてるよ。zshが遅くて重いっていう誤解を与えてる。zshには設定フレームワークやプラグインなんて必要ない。デフォルトの設定をちょっと変えるだけで、その強力な補完機能がすぐに使えるようになるんだ。今はデフォルトを理想以上に調整しないといけないから、みんなこういうフレームワークに流れちゃうんだろうね。

まともなシェルを得るためにどのノブを回せばいいのか、長い時間をかけたくないんだ。oh-my-zshの代わりに、見た目がそこそこ良くて、fzfが統合されてて、'ghost text'の履歴提案があるような代替品があれば、歓迎するよ!

ちょっと気になったんだけど、oh-my-zshの何が悪いの?自分は使ってるけど、特に問題ないし。何か見落としてるのかな?

これ言いに来た。少ない設定行で、バニラzshからomzの機能セットを再現できたよ。自分がomzで使ってた機能にはちゃんと対応してる。

参考までに、同僚の画面でzshを見たことがあるけど、Oh-My-Zshは1. めっちゃ遅いし、2. 使ってる機能の10%も活かせてない感じ。だから、試す気にもならなかった(でも、彼らの fancy setup で動くようにいくつかのワンライナーを直さなきゃいけなかった)。それに、macOSがデフォルトで切り替えたのも驚いた。自分は「oh-my-it's-so-slow-zsh」に乗る気にはならなかったな。一方で、ここでおすすめされてたfish+starshipの組み合わせは面白そう。

シェルなんてそんなもんだよ。1986年からコンピュータを使ってるけど、虹色のデザインやバーチャルペットみたいな「シェルをカスタマイズする」系は全然興味ない。CLIは、GUIやIDEが何らかの理由でサポートしてないことをやるためのもんだし、REPLみたいなインタラクションのために使うんだよね。

それに、StarshipやAtuinみたいなコンパイルされたプログラムを使えば、たくさんの便利な機能を追加できるよ。設定も少なくて済むし、速いし、いくつかのシェルで動くからね。

zshが結構いい補完機能を持ってるなんて知らなかった。fishと比べてどうなの?

最近似たようなことをやったよ。切り替えた初日からプラグインの必要性を感じなかった。fzfを使いこなせば、たくさんのプラグインを置き換えられるよ。gitのブランチ名や仮想環境はstarshipが処理してくれるし。今のカスタム設定は10行にも満たないよ: export HISTSIZE=1000000000 export SAVEHIST=$HISTSIZE setopt EXTENDED_HISTORY setopt autocd autoload -U compinit; compinit source

OMZが遅すぎると思ったから、Preztoに切り替えたよ。Preztoは初めからずっと速いし、デフォルトで有効になってる機能も少ない。もしOMZが遅いと感じるなら、ぜひ試してみて! [0] https://github.com/sorin-ionescu/prezto

zsh用のプラグインシステムってめっちゃ多いよね。コメントを見る限り、Preztoがメインで推奨されてるみたい。でも、いろんな選択肢があるし。https://github.com/sindresorhus/pure?tab=readme-ov-file#inte... を見てみると、例えばzim、zplug、zinit、ziなんかもある。もっと深く調べたり比較したりしたら面白そうだね。Preztoが本当にベストな選択なのか、人気以外の理由は何なのか。とりあえず、いろんなzshプラグインシステムのチートシートがあるこの面白いgistを見つけたよ(ほんとにたくさんある!) https://gist.github.com/olets/06009589d7887617e061481e22cf5a...

ZSHや似たシェルに対して特に反対はないよ。素晴らしいと思うけど、自分には合わない。遅延が致命的で、オートコンプリートエンジンが驚くほどのインタラクティブな待ち時間を引き起こすことが多いから。自分はmksh(環境によってはOpenBSDのKSH)を使って、エイリアスや変数、いくつかのローカル関数以外はほとんど設定しないようにしてる。NFSで認証してマウントしてから操作を実行するAutoFSファイルシステムでfind(1)を誤って実行するような気持ちにはならない。もっと複雑なことが必要なときは、GoやElvishを使ったり、UI要素をhttps://github.com/charmbracelet/gumに委任したりすることもある。シェルはシンプルに保ちたいし、他の複雑さはこれらのプログラムに任せたい。オートコンプリートやその他の機能は、ただで手に入るものじゃないからね。