我只维护一份 bashrc/zshrc,但它帮我省掉了很多麻烦 🧰✨
这篇还是那句话:不讲炫技,不讲“插件大全” 😄
我只讲我这份 ~/.bashrc / ~/.zshrc 怎么在真实场景里省时间、省心、省事故。🚀
如果你是“会一点命令行,但不想天天折腾配置”的人,这篇就是写给你的。☕
先看结果:我省掉了哪些麻烦 ✅
- 换机器不用重配一大坨环境 🖥️➡️💻
- 本地终端、SSH、图形会话不打架 🔌
- 自动化可开可关,不会被反客为主 🎛️
- 少一个工具也不会整段启动报错 🧯
- 每天开机后更快进入“可工作状态” 🛠️
这张图可以一句话概括: 同一份配置,按场景做不同动作。 🧠
麻烦 1:有些场景根本不该加载完整配置 🙅
我以前踩过坑:只是跑个脚本,结果把交互配置全加载了,慢还容易污染环境。😵
现在我第一步就“门禁”:
[ -t 0 ] && case "$-" in *i*) ;; *) return ;; esac
...
[ ! -t 0 ] && return
白话解释:
- 不是交互终端?直接返回 👋
- 不是 TTY?也别继续了 👋
这样脚本干净、终端稳定,很多奇怪问题直接消失。🧹
麻烦 2:macOS/Linux + bash/zsh 容易分叉 🤹
我的做法是: 系统差异只在少数入口分叉,后面尽量复用同一套流程。
比如 Homebrew 前缀统一入口:
if [ "$UNAME" = Darwin ]; then
HOMEBREW_PREFIX=/opt/homebrew
else
HOMEBREW_PREFIX=/home/linuxbrew/.linuxbrew
fi
再手工补齐 brew 相关变量:
export HOMEBREW_CELLAR="${HOMEBREW_PREFIX}/Cellar"
export HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew"
export MANPATH="${HOMEBREW_PREFIX}/share/man${MANPATH+:$MANPATH}:"
export INFOPATH="${HOMEBREW_PREFIX}/share/info:${INFOPATH:-}"
zsh 差异单独放在附加文件:
if [ -n "$ZSH_VERSION" ]; then
[ -f ~/.bashrc.zsh ] && . ~/.bashrc.zsh
fi
这样就不会演变成“bash 一套、zsh 一套、mac 一套、linux 一套”那种维护地狱。🔥
麻烦 3:路径 PATH 越配越乱、越配越长 🧵
我不再手写一堆 export PATH=...,而是分三步:
addToPATH() {
case ":$PATH:" in *:"$1":*) ;; *) PATH="$1:$PATH" ;; esac
}
searchToPATH() {
[ ! -d "$1" ] && return
for item in "$1"/*; do
[ -d "${item}/bin" ] || continue
[ -n "${item##*conda*}" ] || continue
[ -n "${item##*forge*}" ] || continue
PATH="${item}/bin:${PATH}"
done
}
uniqTo() {
content="$(eval "echo \$$1")"
eval "$1=$(echo -n "$content" | tr ":" "\n" | awk '!x[$0]++' | tr "\n" ":")"
}
白话解释:
addToPATH负责“加但不重复”searchToPATH负责“自动扫描工具目录”uniqTo PATH负责“最后统一去重收尾”
长期看,这比手工堆 PATH 稳太多了。📌
麻烦 4:登录后进入工作状态太慢 🐢
我不想每次都手动“开图形环境 -> 开终端 -> 开开发会话”。 所以我加了条件自动化,但只在该自动的场景触发。
if [ -z "$SSH_CONNECTION" ] && [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then
if [ -n "$MYWAYLAND" ]; then
export LIBVA_DRIVER_NAME=nvidia
export __GLX_VENDOR_LIBRARY_NAME=nvidia
export WLR_RENDERER=vulkan
export WLR_NO_HARDWARE_CURSORS=1
if [ -n "$ZSH_VERSION" ]; then
eval 'exec ${=MYWAYLAND}'
else
exec $MYWAYLAND
fi
else
exec startx
fi
fi
重点不是“自动”,而是“有边界地自动” 🎯:
- 本地 TTY1 才自动
- SSH 场景不乱动
- Wayland / startx 都有分支
麻烦 5:tmux / conda 自动化要么太死,要么太乱 🔁
我把它们做成“可逆开关”,用锁文件控制:
VOCALOCK_TMUX="$VOCALOCK"/tmux
VOCALOCK_CONDA="${VOCALOCK}/conda"
切换函数:
toggle() {
if [ -e "$1" ]; then
rm "$1"
else
touch "$1"
eval "$2"
fi
}
totmux() { toggle "$VOCALOCK_TMUX" ontmux; }
toconda() { toggle "$VOCALOCK_CONDA" onconda; }
tmux 启动退化链路:
ontmux() {
[ -n "$TMUX" ] && return
local mytmux="$MYTMUX"
[ ! -x "$mytmux" ] && command -v tmux &>/dev/null && mytmux=tmux
[ -z "$mytmux" ] && return
exec "$mytmux" new-session -A -s main "$SHELL"
}
conda 启动退化链路:
onconda() {
local myconda="$MYCONDA"
if [ ! -d "$myconda" ]; then
if [ -d "${VOCAL}/anaconda3" ]; then
myconda="${VOCAL}/anaconda3"
elif [ -d "${VOCAL}/miniconda3" ]; then
myconda="${VOCAL}/miniconda3"
fi
fi
[ -z "$myconda" ] && return
if [ -f "${myconda}/etc/profile.d/conda.sh" ]; then
. "${myconda}/etc/profile.d/conda.sh"
else
addToPATH "${myconda}/bin"
fi
}
这部分核心就是: 开关可控 + 失败可退化 🛟
麻烦 6:网络和工具链状态不稳定 🌐
我这边网络场景比较多,所以镜像策略也做成可切换:
if [ "$MYNOMIRRORFLAG" != 1 ]; then
export GOPROXY=https://goproxy.cn
export HOMEBREW_API_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/api
export UV_DEFAULT_INDEX=https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
export HF_ENDPOINT=https://hf-mirror.com
fi
此外工具初始化统一走“有就启用,没有就跳过”:
command -v starship >/dev/null 2>&1 && eval "$(starship init "$BASENAME_SHELL")"
command -v zoxide >/dev/null 2>&1 && eval "$(zoxide init "$BASENAME_SHELL")"
这能显著减少“新机器第一天到处报错”的烦躁感。😌
最后:我现在怎么判断一份配置值不值得长期维护 🧭
不是看它有多少技巧,而是看它能不能做到:
- 场景切换时不出戏
- 依赖缺失时不崩
- 尽快把我送进工作状态
如果你也不想在配置上花太多心力,我给一个最实用的起点:
先做“门禁 + 开关 + 退化”这三件事。
很多体验问题,会在这一步直接改善。💡