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

Oh My Zshが無駄を増やす

概要

  • Oh My Zsh は便利だが、起動時の 遅延不要な機能 が多い
  • シンプルな Zsh設定 で十分な機能と高速な起動を実現可能
  • starship でプロンプトを簡単かつ高速にカスタマイズ
  • 履歴検索は fzf によるインタラクティブ検索が効率的
  • Vimモードtmux 活用でターミナル作業効率化

Oh My Zshの問題点とシンプル構成の提案

  • Oh My Zsh(OMZ) は多機能だが、 シェルスクリプト の読み込みで起動が遅くなる問題
  • プラグイン(git, zsh-autosuggestions, zsh-autocomplete)を入れたデフォルト構成で 0.38秒 の起動時間
  • gitリポジトリ内や仮想環境プラグイン利用時、さらに遅延発生
  • 頻繁なタブ・セッションの切替がある場合、 体感で1秒近い遅延
  • 自動アップデート も起動時に数秒かかることがあり、頻繁な更新の必要性も低い
  • 結論: 必要最小限 の設定から始め、必要な機能だけを追加推奨

最小限のZsh設定例

  • HISTSIZESAVEHIST で履歴保存数を大幅増加
  • EXTENDED_HISTORY で履歴にタイムスタンプ付与
  • autocd でcdコマンド省略移動
  • compinit で補完機能初期化
export HISTSIZE=1000000000
export SAVEHIST=$HISTSIZE
setopt EXTENDED_HISTORY
setopt autocd
autoload -U compinit; compinit
  • 上記のみで 十分な補完機能快適な履歴管理

プロンプトカスタマイズとstarship活用

  • プロンプトは starship 推奨、 単一バイナリ で高速動作
  • gitやPython, Rustなどの言語・仮想環境情報も自動表示
  • クラウドサービス表示(aws, gcloud, azure等)は 無効化 で視認性向上
[aws]
disabled = true
[package]
disabled = true
[gcloud]
disabled = true
[azure]
disabled = true
[nodejs]
disabled = true
[character]
success_symbol = '[➜](bold green)'
[cmd_duration]
min_time = 500
format = 'underwent [$duration](bold yellow)'
[directory]
truncation_length = 255
truncate_to_repo = false
use_logical_path = false
  • starship有効化:.zshrcに以下を追加 eval "$(starship init zsh)"

履歴検索の効率化

  • zsh-autosuggestions は入力時に全候補が表示され、視覚的に煩雑
  • fzf をCtrl+Rでバインドし、インタラクティブなファジー検索を利用推奨
source <(fzf --zsh)

起動時間比較

  • シンプル設定後の起動時間: 0.07秒
  • 大幅な高速化を実現

その他のTips・Vimモード

  • Vimユーザー はZshでVimモードを有効化推奨
set -o vi
bindkey -v '^?' backward-delete-char
  • デフォルトはEmacsキーバインドだが、Vim操作で編集効率化

tmux・ターミナルワークフロー

  • tmuxhelix などターミナルベースエディタを活用
  • lazygitやyazi file manager等を ポップアップ表示 で効率的に管理
  • コード・テスト出力を 一時的な分割表示 で同時確認
  • 多数のタブや分割ウィンドウを IDEのウィンドウのように利用

まとめ

  • OMZ不要論 :シンプル構成で十分な機能・高速動作
  • 必要なプラグインのみ 手動ロード で柔軟運用
  • ターミナルワークフローの最適化は 設定の見直し から
  • 質問等はフッター記載の メールアドレス まで

Hackerたちの意見

15年前、大学の初めにoh-my-zshをインストールしたんだけど、その頃はzshがMacのデフォルトじゃなかったんだよね。それがすごく良くて、他のシェルや設定を試してみようって気になったことがない。新しいコンピュータを手に入れたら、まず最初にインストールするものだね。

oh-my-zshを使ってる理由は一つだけ。すぐに良いシェル体験ができて、すぐに作業に取り掛かれるから。新しいマシンでも、新しいリモートホストでも、コンテナでもね。いろいろ試すのに何時間もかけるより、その時間をもっと大事なことに使いたいんだ。

いろいろ試すのに何時間もかける、この記事ではそれらの設定方法を説明してるよ。読むのに5分もかからない。

でも、omzよりも良くて簡単なzimみたいなのも使えるよ。zimだとシェルの立ち上がりがめっちゃ早いし、設定も楽ちんだよ。

じゃあ、https://starship.rsを試してみて。Starshipは同じ「すぐに使える」体験を提供してくれるけど、200ms以上のプロンプト遅延がないよ。一行curl -> あなたのrcファイルに一行追加するだけで、zsh/bash/fish/何でも使える。設定もシンプルで簡単だと思うよ: https://starship.rs/config/ ぜひ試してみて、後悔はしないと思うよ。

数日かけて、基本的なzshの設定を調整したんだ。それ以来、ほとんど設定なしでzshを使ってて、すごく気に入ってる。確かに習得曲線は急だけど、俺はずっとzshを使ってるから、いい時間投資だったと思う。俺の経験では、デフォルトのzsh設定で十分で、カスタマイズもほとんどいらないよ。

俺はただfishシェルを使ってるよ。めっちゃ楽だし。https://fishshell.com/

参考までに、oh-my-zshみたいな非デフォルトの設定を使えるマシンなら、自分のカスタム設定をコピーするだけでもいいと思うよ。oh-my-zshを使う代わりに毎回設定をゼロから書き直すか、デフォルトを使うしかないって言ってるみたいだけど、それはちょっとおかしいと思う。自分の好きな設定ファイルを一度作ってバックアップしておけば、他のマシンでもその設定を使い続けられるし、gitで管理することもできる。最近新しい個人用マシンをセットアップしたけど、ドットファイルを持ってきたら、他のマシンと同じ馴染みのある感じになったよ。

うーん、dotfilesってそのために作られたんじゃなかったっけ?冗談だけど、真面目な話、デフォルトシェルとしてシェルをインストールするのは、.bashrcをコピーするよりも複雑そうだね。

Oh My Zshをやめた理由は一つだけ:めっちゃ遅くて、シェルや気分に影響が出るくらいだったから。タブを開くたびに待たなきゃいけないのがイライラした。だから削除して、Zshを使い続けたんだけど、前に使ってたものが恋しくなったら調べて、Homebrewで簡単にプラグインをインストールした。全部で1時間もかからなかったよ。結局、必要なのは2、3個のプラグインだけだって気づいた。今はシェルが速くて、余計なものもなくて、自分が必要なことをしてくれる。ずっと生産性が上がって、幸せだし、結局この会話の範囲内で何がもっと重要かって言ったら、これ以上のことはないと思う。

他の多くの人と同じように、デフォルトの設定でoh-my-zshを使ってるだけだよ。実際、git用のプラグイン一つしか使ってないし、スタートアップの遅延を避けるためにカスタム関数を自動で読み込むようにしてる。384行の設定でoh-my-zshを使った結果はこんな感じだよ:$ hyperfine -N "zsh -lc 'exit 0'" "zsh -c 'exit 0'" ベンチマーク1: zsh -lc 'exit 0' 時間(平均 ± σ):54.5 ms ± 6.3 ms [ユーザー: 10.2 ms, システム: 14.3 ms] 範囲(最小 … 最大):38.1 ms … 64.9 ms 78回 ベンチマーク2: zsh -c 'exit 0' 時間(平均 ± σ):6.5 ms ± 1.4 ms [ユーザー: 0.8 ms, システム: 1.3 ms] 範囲(最小 … 最大):3.9 ms … 14.2 ms 424回 スタートアップ時間が380msってのはすごいよね。oh-my-zshだけが原因じゃない気がするけど。

gitリポジトリでベンチマークを試してみて。

extract、z、fzfも試してみて!

zsh -l はログインシェルを起動するから、zshrcが読み込まれなくてoh-my-zshが初期化されないんだよね。zsh -ic exit を試してみて。これだとexitを実行する前にzshrcが読み込まれるはず。とはいえ、zsh -ic exit の時間はインタラクティブシェルのパフォーマンスを測るのにはあんまり意味がないよ。詳しくは https://github.com/romkatv/zsh-bench#how-not-to-benchmark を見てね。

zshの起動時間をベンチマークするにはzprofを使うのがいいよ。これを~/.zshrcに追加してみて:zmodload zsh/zprof .. あとは自分のzsh設定 .. zprof そしてターミナルを再起動してね。

zshの起動パフォーマンスを気にする人には、romkatv(powerlevel10kの作者)のzsh4humansをチェックする価値があるよ:https://github.com/romkatv/zsh4humans。これを使うと、シェルが完全に初期化される前にプロンプトをレンダリングすることで、即座に起動できる。これを導入してから、シェルの設定をいじるのはやめたし、zsh4humansがメンテナンスモードなのも逆に良いことだと思ってる。無駄にzshrcをリファクタリングする時間を浪費しなくて済むからね。

Oh My Zshの主な問題は、シェルの起動時間に影響を与える不要な膨張をたくさん追加することだよね。うわぁ!その+0.5秒の遅延で、猫がどこでも死んじゃうよ。シェルの起動時間を微調整しなきゃ!!!それとも、単にbashとKDE konsoleを使って、例えば10タブ開けばいいのかも。俺はそのセットアップでずっとやってるし、正直言ってbashは簡単なアクションのラッパーとして使ってるだけで、実際の仕事は無数のエイリアスや主にrubyスクリプトでやってるんだ。でも、oh-my-zshによる+0.5秒の遅延を気にしてる人がいるなんて知らなかったよ。膨張!なんてこった!

それに、一人が一日に何個のシェルを開けるんだろう?俺は良い日には一日一回、たくさんの未計画のサブプロジェクトの作業が同時に進行する必要がある時は、20回くらい開くこともあるよ。

ターミナル中心のワークフローだと、一日に何十回もシェルを開くことになるよね。コマンドを一つ実行して、前のコマンドから情報が必要だと気づいたとき、最も早くその情報を得る方法は別のターミナルを開いて、必要なコマンドを打ち込むことが多い。あるいは、ウィンドウでスクロールアップした別のコマンドの出力が必要なときもね。一般的に、重要な情報を持ったタイルのモザイクができるから、他の3つや4つのウィンドウの情報を使うために新しいタブを開くことになる。シェルの起動は、単にいくつかのターミナルを待つことではなく、各シェルが長いライブワークフローの小さな部分であることに関係してる。シェルを待つのが1秒でも、コマンドの一部を埋めるために待つのはすごく嫌な感じがする。nushellがこの非効率を減らすのに役立つと思うけど、テキスト出力を解析してパイプでつなぐより、bashコマンドを手動でつなげる方がずっと簡単だよね。

starshipを使ってfishシェルに切り替えたよ。fishは自動補完と構文ハイライトが標準でついてるから、結構便利なんだ。これがomgzhで使ってる主な機能だから、fishは俺にとって安全な選択だったよ。https://ruky.me/moving-from-zsh-to-fish-nixos-darwin/

それに、たぶん全くカスタマイズしなくてもいいよ。初めから十分すぎるくらい良いから。

fishもPOSIXじゃないから、これがずっと問題なんだよね。俺はzsh+starshipと自分の超ミニマルな初期設定、zshの自動補完と構文ハイライトのプラグインを使ってる。完璧なセットアップではないけど、fishが「ただ動けばいいのに」って思うことが多い。自分のセットアップのために「ワークアラウンド」を探さなきゃいけないことが頻繁にあった。25年経って、やっと分かってきたけど、自分のスタイルに合ったzshrcとmachine-init.shをキープしてる。fish+starshipでかなり簡素化できると思うけど、まだそこまで行ってないんだよね。

そうだね。俺は何十年もzshを使ってて、設定に結構な時間と感情を注いできたんだけど、去年の1月に試しにfishに乗り換えたら、これがハマっちゃった。完璧ではないけど、HEREDOCがないのはたまにイライラするし、バックグラウンドでブロックを使えない(例えば {x}&)から、スクリプトで非同期処理が簡単にできないのがちょっと面倒。zshには高度な機能がたくさんあって(少なくともシェルとしては)、複雑なスクリプトを書くのに便利なんだけど、fishスクリプトを書くときにはそれが恋しくなることもある。でも、実際には長年それらを使い倒してきたから、今は「単一のバイナリにビルドする」言語を使う方が多いかも。もう少し安定したらnushellに乗り換えるつもり。俺の経験ではランタイムは安定してるけど、機能やコマンド名はまだ落ち着いてない感じ。構造化データを扱うアイデアはすごく気に入ってるけどね。

わからないな。俺のzsh設定は90行で、プラグインは3つ(compinit、vcs-info、edit-command-line)使ってて、起動から終了までの時間は0.32秒だよ。大きな古いリポジトリで作業すると、どこでラグが出るかすぐにわかる(俺はEmacsのソースコードでこれを学んだ)んだけど、jujutsuの現在のブランチを取得するのに約5秒かかる。Gitはこの点では速いけど、それでも約0.3秒かかる。starshipはあんまり好きじゃない(一般的に派手なコマンドライン変数は使わないから)けど、そういう問題はawesome bktキャッシュユーティリティで解決できると思う。[0]。ライブリーディングの代わりに、bktに長いTTLでキャッシュさせて、積極的に非同期でリフレッシュさせればいいんじゃないかな。俺の予想では、Starshipはまさにそれをやってると思う。[0]: https://github.com/dimo414/bkt

Vimユーザーには、ZshでVimモードを有効にすることをお勧めします。コマンドの編集がずっと早くなります。俺もVimのヘビーユーザーだけど、これには同意しないな。デフォルトのreadlineで十分だと思うよ。単一行のコマンドには問題ないし(基本的なコマンドには慣れておく必要があるけど、C-a/u/k/l/w...)。長いコマンドを$EDITORで編集したいときは、bash/zshでC-x C-eを使えばいいし(FishではM-v)。実際、同僚とペアプログラミングするとき、彼が短いコマンドを編集するのが俺より遅いと思うのは、モードを変更し続けなきゃいけないからだと思う。

Vimモードを有効にした後にreadlineのバインドを再追加するのが好きで、挿入モードはたまにしか使わないようにしてる。C-x C-eは本当に素晴らしいと思う。大きな一行の編集が必要なときは、ついそれに手が伸びちゃうね。

bash/zshではC-x C-eができるよ(FishではM-v)。ありがとう、知らなかった!

5年前にzshに切り替えたとき、俺もデフォルトの設定で始めたよ。OPの投稿にはシェルの履歴について重要なことがいくつか書かれてないと思うんだ。例えば、以下の設定ね:

  • setopt HIST_IGNORE_ALL_DUPS # 重複エントリを追加しない
  • setopt HIST_IGNORE_SPACE # スペースで始まるコマンドを無視する
  • setopt HIST_REDUCE_BLANKS # 不要な空行を削除する

役立つことをするプロンプトを自分で作ることもできるし、starshipを使わなくても大丈夫。自分だけのzshプラグインマネージャーを数行のシェルスクリプトで作ることもできるよ。fast-syntax-highlightingは、コマンドを入力しているときにリアルタイムでフィードバックを得られる便利なプラグインだ。これらのことはここに書いてあるよ:https://nickjanetakis.com/blog/i-recently-switched-to-zsh-an...。投稿は5年前のものだけど、今でもほとんど同じことをやってる。あれから進化して、専用のVim zshプラグインを使うようになったけど、これがデフォルトのzshのキーバインドよりもずっと良くなった。fzfの中でzshのタブ補完を表示する別のプラグインもあるよ。タブ補完のデモ動画はここにある:https://nickjanetakis.com/blog/hooking-up-fzf-with-zsh-tab-c....

だからこそfishに切り替えたんだ。fishは自分が望むようにプリコンフィグされてるわけじゃないけど、デフォルトに慣れちゃったから今は全然問題ないし、シェルの設定について考えることもなくなった。

このアプローチの追加の利点は、どんなホストにも簡単にfishをインストールできて、今まで使ってた設定に合わせる必要がないってことだね。

今はfishを使ってるけど、正直言って全体的にいいシェルとシェル言語だよ。