Fish Shell 命令速查表 - Fish Shell 常用命令与配置大全
Fish 把语法高亮、自动补全、历史模糊搜索做成了默认行为,装完就能用,这是它和 Bash 最大的区别——不是功能更多,而是省掉了配 oh-my-zsh 那几步。真正需要下功夫的是语法差异:Fish 的 if/for/while/switch/function 都用 end 收尾,变量用 set 而非 export,列表与索引的写法也和 Bash 不同,数组下标从 1 开始。迁移时最容易出错的往往不是交互命令,而是把 .bashrc 里的片段直接搬过来。表里按变量作用域、流程控制、函数别名、字符串管道、配置主题、历史快捷键分组列出对应写法,遇到 Bash 习惯时先翻这张对照表,再决定是改脚本还是加一层 sh -c 兜底。
典型使用场景
面向从 bash/zsh 切到 fish 之后被语法绊住的人。fish 不是「换个提示符的 bash」:变量必须用 set 命令赋值而不是 VAR=value 写法,没有 $(...) 之外的 process substitution,列表默认按整体拼接而不做单词切分,.bashrc 直接 source 过来几乎必报错。本表把这几处真正会卡人的差异和三档变量作用域(local/global/universal)讲清楚,再补上历史搜索、字符串处理与 fisher 插件安装,够你在一周内完成迁移。
变量与作用域 7
set name "John"echo $nameset -x PATH /usr/local/bin $PATHset -U fish_user_paths /usr/local/bin $fish_user_pathsset -l local_var "value"set -g global_var "value"set -e name流程控制 5
if test -f file.txt
echo "exists"
endif test $count -gt 5
echo "many"
else
echo "few"
endfor file in *.txt
echo $file
endwhile read -l line
echo $line
end < file.txtswitch $status
case 0
echo "success"
case "*"
echo "failed"
end函数与别名 7
function greet
echo "Hello $argv"
endfuncsave greetfunctionsfunctions greetalias cls="clear"abbr -a gco "git checkout"funced greet字符串与管道 6
string length "hello"string split "," "a,b,c"string join ";" "a" "b" "c"string replace "old" "new" "hello old"string match -r "^\d+" "123abc"echo "data" | string upper配置与主题 6
fish_configfish_config theme choose Nordset -U fish_greeting ""fish_update_completionscat ~/.config/fish/config.fishfisher install jorgebucaran/autopair.fish命令历史与快捷键 5
historyhistory search "git"history delete "rm -rf"Ctrl+RAlt+← / Alt+→参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
set -x / -g / -U / -l / -e | 依次为导出(环境)变量、全局变量、通用(跨会话持久)变量、局部变量与删除 | set -U fish_user_paths /usr/local/bin $fish_user_paths |
fish_greeting | 登录时的欢迎语,设为空字符串即可去掉启动横幅 | set -U fish_greeting "" |
abbr -a | 命令缩写,输入前缀后自动展开且不进入历史,比 alias 更适合替代命令 | abbr -a gco "git checkout" |
string | 内置字符串工具子命令,替代 bash 里的 cut/sed/tr/grep 组合 | string split "," "a,b,c" |
funcsave | 把当前交互式定义的函数持久化进配置文件,重开终端仍在 | funcsave greet |
易错点与避坑指南
现象把 .bashrc 里 export PATH=... 直接搬到 fish,执行后 PATH 没变,PATH 里出现一个字面量。
原因fish 里 export VAR=value 不是合法语法,变量必须用 set 命令赋值并带 -x。
处置改成 set -x PATH /usr/local/bin $PATH;要永久生效用 set -U fish_user_paths /usr/local/bin $fish_user_paths。
现象交互式定义的函数关掉终端就没了,下次又要重打一遍。
原因fish 不会自动把交互式函数写回配置文件。
处置定义后执行 funcsave greet 持久化;改动已保存的函数时用 funced greet 编辑。
现象启动时报 fish: Unknown command: [... 一堆语法错误。
原因把 bash 的 [ ] 条件语法直接搬过来,fish 用 test 而不是方括号,且 end 收尾结构不同。
处置改写成 if test $count -gt 5 / else / end 这类 fish 原生结构,逐块替换。
现象alias 定义后想禁用它时 alias name 报错说不存在。
原因fish 里 alias 是函数,删除要用 functions -e name,而不是 bash 的 unalias。
处置用 functions -e name 删除;对命令类替换优先改用 abbr -a,展开更干净。
现象PATH 里手动加的目录重启终端后又没了。
原因用 set -x 写入的只是本次会话的导出变量,没有落到持久化的 universal 变量。
处置用 set -U fish_user_paths /usr/local/bin $fish_user_paths 让它跨会话保留。
排障路径
1确认配置到底生效了没有
cat ~/.config/fish/config.fishfish 配置只读这一个文件(不含 .bashrc);改完执行 source ~/.config/fish/config.fish 立即重载。
2找一条以前打过的长命令
history search "git"等价于 Ctrl+R 的交互式增量搜索;history delete "rm -rf" 可清掉危险记录。
3查某个函数/别名的定义
functions && functions greetfunctions 列出全部,functions greet 打印单条定义,据此判断它是否被覆盖。
4装插件
fisher install jorgebucaran/autopair.fishfisher 是 fish 的插件管理器;装完检查 functions 确认插件函数已被加载。
命令示例
导出一个环境变量并查看它
set -x PATH /usr/local/bin $PATH-x 等价于导出,子进程能继承;这是替换掉 bash 里 export PATH=... 的正确 fish 写法。
把一个目录永久加入 PATH
set -U fish_user_paths /usr/local/bin $fish_user_paths通用变量会落盘并跨会话生效,反复执行不会重复累积同一目录。
按逗号切分字符串
string split "," "a,b,c"string 是 fish 内置的字符串工具,能替代 bash 里 cut、sed、tr、grep 的组合。
用命令缩写替代别名
abbr -a gco "git checkout"输入前缀后按空格即展开,且不像 alias 那样进入历史记录,适合替代命令。
常见坑与注意事项
- 不要把 bash 的 export PATH=... 直接粘进 fish,fish 没有这条语法,PATH 里会出现字面量而目录没加上。
- fish 里所有赋值都要走 set 命令,VAR=value 形式不会创建变量。
- if / for / while / function / switch 都必须用 end 收尾,照搬 bash 的 fi、done、esac 会直接报语法错。
- 交互式定义的函数不会自动持久化,务必 funcsave 一次,否则重开终端全部白写。
- 想让 PATH 改动长期有效就用 set -U fish_user_paths,只在当前会话 set -x 的效果关掉终端即消失。
提示
- Fish 的 if/for/function/switch 用 end 结尾,不需要 fi/done/esac。
- set -U 设置通用变量,持久化到配置文件,所有 Fish 会话共享。
- Fish 开箱即用自动补全,按 Tab 即可,按 Alt+→ 接受建议。
- fisher 是 Fish 的插件管理器:curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher。
- abbr 比 alias 更轻量,输入缩写后按空格会自动展开为完整命令。
- Fish 不兼容 POSIX Shell 语法,不能直接用 bash 脚本,但语法更直观。
- fish_config 用 fzf 交互改 PATH:set -U fish_user_paths $fish_user_paths ~/go/bin,永久生效且不重复写入。
- fish -c "命令" 可在脚本或测试里跑单条 Fish 命令,比开交互 shell 更快验证语法。
- 用 set -q 判断变量是否存在:set -q VAR; and echo yes,避免 $VAR 未定义时展开报错。
常见问题
为什么我把 .bashrc 里的 export PATH=... 搬到 fish 里就没效果?
fish 不认 VAR=value 这种写法,也不会解析 export 这条命令,fish 会把整行当成一个普通命令名去找,然后报未知命令,于是 PATH 里可能出现一个字面量。fish 里的正确写法是 set -x PATH /usr/local/bin $PATH,-x 表示导出为环境变量,变量以美元符号加名字引用。
fish 里的条件判断和循环为什么不用 fi、done?
因为 fish 用统一的块结束关键字 end,if、for、while、function、switch 全都用 end 收尾,不需要成对的 fi/done/esac。迁移时看到 if 后面没有 end 之外的 fi、for 后面也没有 done,就是这个原因。
我手动往 PATH 里加的目录,重开终端后就没了?
因为那只是当前会话的变量,没有持久化。用 set -U fish_user_paths /usr/local/bin $fish_user_paths 把目录写进通用变量,它会存到配置里、跨会话保留,而且重复设置不会造成 PATH 里出现多份同样的条目。想在图形界面里改,fish_config 提供的 PATH 页签做的也是同一件事。
在交互式终端里定义好的函数,关掉终端就消失了?
交互式定义的函数只存在于当前会话,除非你显式保存。定义完执行 funcsave greet,函数体就会被写进配置文件,下次开终端还在。写错了用 funced greet 交互式重新编辑,改完同样要 funcsave 才会落盘。
fish 的 -l、-g、-U、-x 四个标记分别管什么?
都是 set 的作用域开关:-l 局部变量,只在当前函数或块内可见;-g 全局变量,当前会话共享;-U 通用变量,写入配置文件并跨会话持久;-x 导出为环境变量,子进程能读到。函数内部用 -l 避免污染全局,PATH 这类要传给外部命令的才用 -x,要跨终端保留的用 -U。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。