Skip to main content

Command Palette

Search for a command to run...

.bashrc をやめた

シェル環境を3層に分解した話

Published
2 min read
	.bashrc をやめた

はじめに

ある朝、j コマンドが消えた。

zoxide のエイリアスとして使っていたはずなのに、command not found と返ってくる。Ghostty では動くが、VSCode の統合ターミナルでは動かない。Zed では挙動がまた違う。

「なぜ動くか説明できない環境」の完成だった。

これは、.bashrc に設定を積み上げ続けた結果の話だ。そして、それをやめることで得た「決定性(determinism)」の話でもある。


Before:.bashrc 全部盛り時代

Linux 開発を始めた当初、便利なツールを導入するたびに .bashrc に書き足していった。

# .bashrc(肥大化した状態)
eval "$(starship init bash)"
eval "$(zoxide init bash)"
eval "$(fzf --bash)"
eval "$(keychain --quiet --eval --agents ssh id_ed25519_work id_ed25519_personal)"
source ~/.bash_aliases
export PATH="\(HOME/.local/bin:\)PATH"
# ... secrets, completions, etc.

alias、completion、環境変数、ツールの初期化がひとつのファイルに混在していた。

これが引き起こした問題は主に3つだった。

① PATH の不整合

ツールによって「パスが通っていたり通っていなかったりする」状態になった。ターミナルを新しく開くたびに、動く/動かないが変わることがある。

② ターミナル間の挙動差異

Ghostty では動くコマンドが VSCode の統合ターミナルでは動かない。j コマンドの消失はその典型だった。

③ 再現性の欠如

「なぜ動くか」を説明できなくなった。動いているのが設定のおかげなのか、過去に実行した何かのおかげなのか、もう分からない。


気づき:Shell ≠ Environment

問題を整理していて、あることに気づいた。

Shell ≠ Environment

Shell = UI(インターフェース)

Environment = 実行条件

.bashrc が「OS 標準のシェル設定」と「開発環境の初期化」を同時に担っていた。これが混乱の根本だった。

問題はツール(zoxide や starship)ではなく、初期化経路の混在にあった。特に「login shell」と「interactive shell」で読まれるファイルが異なるという事実が、ターミナルごとの挙動差異を生んでいた。


After:3層に分解する

この気づきをもとに、環境を3層に分解した。

bash    = OS標準・保全層
zsh     = 開発環境層
terminal = 表示層(すべて zsh -l に統一)

bash を保全層に戻す

.bashrc を初期化した。

cp /etc/skel/.bashrc ~/.bashrc

残したのは HISTSIZE の拡張だけ。開発用の設定はすべて撤去した。

zsh に開発環境を集約する

開発ツールの初期化は .zshrc に移した。

# ~/.zshrc
eval "$(starship init zsh)"
eval "$(zoxide init zsh)"
source ~/.zsh_aliases
export PATH="\(HOME/.local/bin:\)PATH"

alias も .zsh_aliases として分離した。

ターミナルをすべて zsh -l に統一する

各ターミナルの設定を変更し、起動シェルを統一した。

Ghostty

command = /usr/bin/zsh -l

VSCode

"terminal.integrated.profiles.linux": {
  "zsh": {
    "path": "/usr/bin/zsh",
    "args": ["-l"]
  }
},
"terminal.integrated.defaultProfile.linux": "zsh"

Zed(1.0.0 仕様)

"terminal": {
  "shell": {
    "with_arguments": {
      "program": "/usr/bin/zsh",
      "args": ["-l"]
    }
  }
}

WezTerm(~/.wezterm.lua

local wezterm = require 'wezterm'
local config = {
  default_prog = { '/usr/bin/zsh', '-l' },
  font = wezterm.font('JetBrainsMono Nerd Font'),
  font_size = 13.0,
  color_scheme = "Dracula",
  enable_tab_bar = false,
}
return config

WezTerm は default_prog に配列形式でシェルと引数を渡す。フォントもここで統一できる。


ハマりどころ集

移行の過程でいくつか詰まった点を記録しておく。

VSCode だけアイコンが豆腐になる

症状:

Ghostty → OK
Zed     → OK
VSCode  → アイコンが □(豆腐)

原因は、VSCode のターミナルフォントが別設定になっていること。

"terminal.integrated.fontFamily": "JetBrainsMono Nerd Font Mono"

を追加して解決した。

フォント名の「設定名」と「実体名」がズレている

設定名: JetBrainsMono Nerd Font Mono
実体:   JetBrainsMono NFM

Ghostty は fontconfig が解決してくれるので問題ない。WezTerm や Zed では JetBrainsMono NFM と実体名で指定する必要がある場合がある。

j コマンドが消えた

.bash_aliasesalias j='z' と書いていたが、zsh 移行後は .zsh_aliases に移す必要があった。

# ~/.zsh_aliases
alias j='z'
alias ji='zi'

\(0\)SHELL の表示が違う

echo $0      # → zsh
echo $SHELL  # → /bin/bash

$SHELL はログインシェルの情報であり、現在起動しているシェルとは異なる場合がある。

export SHELL=/usr/bin/zsh

.zshrc に追加して統一した。


成果

Before: .bashrc に全部盛り → 環境が不確定
After:  bash=保全 / zsh=開発 / terminal=表示層 → 決定性を回復
  • どのターミナルから起動しても同じ環境
  • PATH 問題が消滅
  • デバッグ対象がアプリケーション自体に限定できるようになった

「なぜ動くか説明できる環境」になった、というのが最大の成果だと思っている。


おわりに

.bashrc をやめることは、ツールを捨てることではなかった。
「環境に対する責任の所在を明確にすること」 だった。

Shell は UI だ。Environment は実行条件だ。この2つを同じファイルに押し込めていたことが、すべての混乱の源だった。

次の記事では、この移行直後に Obsidian Git の SSH 認証が壊れ、ssh-agent と Flatpak サンドボックスを相手に格闘した話を書く。

1 views

More from this blog