从 Fish 迁移到 Zsh:配置与函数转换
Fish → Zsh 迁移笔记
记录了从 fish shell 逐步迁移配置到 zsh 的过程和经验。
目录
Starship 多 shell 独立配置
原理
Starship 默认读 ~/.config/starship.toml,所有 shell 共用。通过 STARSHIP_CONFIG 环境变量让不同 shell 各用各的配置。
步骤
- 复制出多份配置:
1 | |
- 在各 shell rc 中指定配置:
Fish (~/.config/fish/config.fish):
1 | |
Zsh (~/.zshrc):
1 | |
关键点
STARSHIP_CONFIG必须在starship init之前设置- Starship 配置查找优先级:
$STARSHIP_CONFIG→~/.config/starship.toml - 设了
STARSHIP_CONFIG后,旧的starship.toml不再被读取
配色快速替换
不改布局只换色,只需改 [palettes.colors] 里的十六进制色值。
已知问题:分隔符空白
Starship 的 format 字符串中分隔符写死,但中间的模块可能为空(如 git 不在仓库时、语言版本不匹配时),导致 双分隔符。无优雅解法,要么忍受要么用 $all 自动格式(但会失去定制的渐变效果)。
环境变量同步
Fish 的 set -gx 对应 Zsh 的 export:
| Fish | Zsh |
|---|---|
set -gx VAR value |
export VAR=value |
set -gx PATH $PATH /new/path |
export PATH="$PATH:/new/path" |
set -p PATH ~/.local/bin |
export PATH="$HOME/.local/bin:$PATH" |
需要同步的变量直接从 ~/.config/fish/config.fish 搜索 set -gx,翻译后加到 .zshrc:
1 | |
x-cmd 跨 shell 支持
x-cmd 核心是 bash 脚本(~/.x-cmd.root/bin/___x_cmdexe_exp),fish 通过 rc 文件包装。zsh 需要手动创建包装函数和 PATH。
添加到 .zshrc
1 | |
关键环境变量
___X_CMD_REAL_CALLER_SHELL=zsh— 告诉 x-cmd 当前是哪个 shell___X_CMD_RUNMODE=9— 交互模式- fish 的
set -g ___X_CMD_REAL_CALLER_SHELL fish只在 fish 会话内有效,zsh 看不到
函数翻译对照
Fish 函数定义翻译为 Zsh 函数:
| Fish | Zsh |
|---|---|
function name |
name() { ... } |
$argv |
"$@" |
command foo $argv |
command foo "$@" |
if not set -q VAR |
if [ -z "$VAR" ] |
| `eval … | source` |
builtin cd -- "$dir" |
builtin cd -- "$dir" |
and / or |
&& / ` |
示例:cat → bat
1 | |
↓
1 | |
陷阱:别名与函数冲突
oh-my-zsh 预设了一些别名(如 alias ls='ls --color=tty'),zsh 不允许函数和别名同名。定义同名函数前必须先 unalias:
1 | |
也适用于 cat、grep 等 oh-my-zsh 可能预设别名的命令。
示例:yazi 文件管理器
1 | |
↓
1 | |
示例:conda 按需加载
Fish 用 conda shell.fish hook,Zsh 用 conda shell.zsh hook:
1 | |
示例:中文函数名
1 | |
缩写/别名翻译
Fish 的 abbr(输入后展开)Zsh 没有原生等价物,用 alias 近似替代:
| Fish abbr | Zsh alias |
|---|---|
abbr grub 'LANGUAGE=... sudo grub-mkconfig ...' |
alias grub='LANGUAGE=... sudo ...' |
abbr fa fastfetch |
alias fa='fastfetch' |
abbr reboot 'systemctl reboot' |
alias reboot='systemctl reboot' |
abbr lsfg 'LSFG_PROCESS="miyu"' |
alias lsfg='export LSFG_PROCESS=miyu' |
区别:fish 的
abbr输入后按空格才展开,可以预览后再确认;zsh 的alias直接替换执行,没有预览步骤。
终端状态管理
问题
fish 在每次命令执行后自动恢复终端设置。zsh 不会,子进程留下的”脏”终端状态会直接继承。
典型场景:sl(蒸汽火车动画)通过管道传给 lolcat(彩虹色)后,sl 检测到 stdout 不是 TTY,行为异常,退出时没有恢复 raw 模式等终端设置。zsh 继承了这种脏状态,导致后续命令(如 shorin)的输出列对齐错乱。
解决
对有副作用的命令,函数内手动恢复终端:
1 | |
| 恢复命令 | 作用 |
|---|---|
tput sgr0 |
重置文字颜色、粗体等显示属性 |
stty sane |
恢复终端行设置(raw/cooked、回显等) |
两者都不清屏。
通用建议
迁移任何涉及终端控制的命令(动画、TUI、管道穿过色工具)时,在 zsh 包装函数末尾加上 tput sgr0; stty sane 2>/dev/null。这能避免终端状态污染导致后续命令输出错乱(如 column 列对齐失败)。
注意:fish 这类问题不会出现,因为它每次命令后自动恢复终端。zsh 需要手动处理。
清理提示
写完配置后检查语法:
1 | |
无输出 = 语法正确。生效:exec zsh。