fish (简体中文)
fish是“friendly interactive shell”的缩写,是一个“交互式的、对用户友好的 命令行shell”。
fish 被有意设计成不完全与 POSIX 兼容。fish 的作者们认为 POSIX 中存在一些缺陷和矛盾,并通过 fish 简化的或不同的语法解决这些问题。因此,即使简单的 POSIX 兼容的脚本也可能需要较多的修改──甚至完全重写──才能在 fish 中运行。
安装
安装 fish 软件包。或者安装开发版的 fish-gitAUR。
安装完成这后,输入 fish
即可进入 fish shell。
要查看帮助文档,在 fish 中输入 help
,文档将会在浏览器中打开。建议用户至少读完文档中“Syntax overview”这一节内容,因为 fish 的语法和其他 shell 的并不一样。
在系统中配置 fish
需要考虑的是:是把 fish 设置为默认 shell,也就是用户登录时直接进入的 shell,还是通过当前的默认 shell 启动 fish,并只在交互模式下使用 fish。这里,我们假设当前的默认 shell 是 Bash。
- 把 fish 设为默认shell:这种方式需要用户对 fish 的运行机制及其脚本语言有些基本的了解。用户需要把当前的初始化脚本和环境变量移动到 fish 的环境中。#将 fish 设为默认 shell 中有具体的步骤。
- 只把 fish 用作交互式shell:这种方法“破坏性”较小。Bash 会照常运行所有的初始化脚本,并在此基础上启动 fish。#仅将 fish 用作交互式 shell 中有具体的步骤。
将 fish 设为默认 shell
如果你决定把 fish 设为默认的 shell,首先你需要将你的用户的 shell 改为/usr/bin/fish
。参照 Command-line shell#Changing your default shell 中的步骤。
下一步是把 Bash 的几个初始化脚本中的操作和配置用 fish 的方法和工具重写,这些脚本分别有/etc/profile
、~/.bash_profile
、/etc/bash.bashrc
和~/.bashrc
。
需要特别关注的是,在登录到 fish 中后,你需要尽快检查、调整环境变量$PATH
的内容。在 fish 中,$PATH
是一个全局环境变量:全局表示作用范围包含所有函数,并且会在重启的时候被清除;环境变量则意味着它对 fish 的所有子进程都是可见的。相较于修改直接修改 $fish_user_path
,现在更推荐在配置文件中使用 fish_add_path 来设置路径,比如
$ fish_add_path -p /路径_1 /路径_2 /路径_3
会将这三个路径添加到搜索路径的头部。
仅将 fish 用作交互式 shell
如果不将 fish 设为默认 shell,就能照常运行 Bash 的初始化脚本。这能够保证用户当前的环境变量不受影响并且在 fish 中也能使用,因为 fish 是作为 Bash 的子进程运行的。下面是几种只把 fish 用作交互式 shell 的方法。
通过 .bashrc 启动 fish
保持默认 shell 为 Bash 不变,然后添加exec fish
到合适的 Bash 配置文件中,比如.bashrc
。用这种方法,Bash 会正常执行/etc/profile
和/etc/profile.d
中的所有配置文件。相对于后面的几种方法,这种是最通用的,因为这种方法在本机计算机和 SSH 远程计算机上都能使用。
- 在这种配置下,如要使用 Bash 而不是接着启动 fish,需要使用
bash --norc
,以防止Bash加载~/.bashrc
之后执行exec fish
。 - 要让类似于
bash -c 'echo test'
中的命令在 Bash 中执行而不是启动 fish,你可以将exec fish
换为if [ -z "$BASH_EXECUTION_STRING" ]; then exec fish; fi
。 - 在父进程不是 fish 的情况下才起动 fish:这种方法可以在更方便地切换到 Bash 的同时继续使用
~/.bashrc
中的配置。if [[ $(ps --no-header --pid=$PPID --format=cmd) != "fish" ]] then exec fish fi
使用终端模拟器的选项
另一种方法是在启动终端模拟器时通过添加命令行选项来启动fish。对于大部分的终端,这个选项是 -e
。比如,要打开 gnome-terminal 并运行fish,可以将 gnome-terminal 的快捷方式改为:
gnome-terminal -e fish
对于不支持设置 shell 的终端模拟器,比如lilyterm-gitAUR,则需要这样:
SHELL=/usr/bin/fish lilyterm
另外,有些终端可以在设置或配置文件中将 fish 设为默认 shell。
使用终端复用器的选项
要将 fish 设为 tmux 启动的默认 shell,在~/.tmux.conf
中加入这行:
set-option -g default-shell "/usr/bin/fish"
当 tmux 启动时,就会自动进入 fish。
配置
fish的配置脚本保存在~/.config/fish/config.fish
。这个文件与 .bashrc
相似,当每次启动时,fish会执行这个文件中的命令。需要注意的是,如果需要设置长期保留的变量,应该将这个变量设为一个全局变量,而不是将它定义在这些配置脚本中。
用户定义的函数保存在~/.config/fish/functions
中,文件名为函数名.fish
。
网页界面
可以在 fish 的交互式网页配置页面中修改配色、提示符、函数、变量、历史记录和快捷键:
$ fish_config
在 IPv6 被完全禁止的环境下,网页配置界面或许不能起动。参见[1] 和 IPv6#Disable IPv6。
命令补全
fish 可以通过解析 man 的数据生成自动补全规则,这些自动补全规则被保存在~/.config/fish/generated_completions/
。可以运行下面的命令自动更新补齐规则。
$ fish_update_completions
你也可以在 ~/.config/fish/completions/
目录下放置自己定义的补全规则。/usr/share/fish/completions/
中有更多的例子。
对 Arch Linux 来说, pacman, pacman-key, makepkg, cower, pbget, pacmatic 这些命令的自动补全规则已经在内置在 fish 中了,因为 fish 在开发的时候就包含了很多命令的补全规则。fish 的内存管理足够智能,不会因为命令补全产生负面影响。
提示与技巧
命令替换
fish 没有 Bash 式的历史记录替换功能(如 sudo !!
)。fish 的开发者在 fish faq 中建议使用交互式的方式调用历史记录:上
方向键可以按整条命令回顾历史,而Alt+上
可以回顾命令的单个参数。Alt+S
会在整条命令的最前面加上 sudo
。
不过,fish wiki 中介绍了一些替代方法。虽然这些方法提供的历史替换功能并不完整,但可用的有 !!
(替换上一条命令)和 !$
(替换上一条命令的最后一个参数)。
串联命令
在低于 3.0 的版本中,fish 并未实现串联命令符号 &&
和 ||
,推荐使用 ; and
和 ; or
语法来实现相似的效果。也可以参照 fish wiki,设置按键绑定来自动替换符号。
取消问候语
默认情况下,每次启动时 fish 都会打印问候语。如要不显示问候语,可以在 fish 中运行:
set -U fish_greeting ""
让 su 默认启动 fish
如果 su 目标用户的默认 shell 是 Bash,但是你想使用 fish 作为 shell 的话,可以添加一个 su
函数覆盖默认的 su 命令,在切换用户的时候自动使用 fish:
function su /bin/su --shell=/usr/bin/fish $argv end
登录 fish 时自动起动 X
把下面配置添加到 ~/.config/fish/config.fish
,即可在登录 tty1 的时候自动启动 X。
# Start X at login if status --is-login if test -z "$DISPLAY" -a $XDG_VTNR = 1 exec startx -- -keeptty end end
如果在使用 fish 作为交互 shell,需要把例子中的 is-login
换为 is-interactive
。
在提示符中增加 git 状态
当你处在一个 git 目录中时,如果你想在 fish 的提示符中显示分支和修改的相关信息,可以仿照以下的例子编写 fish_prompt
函数:
~/.config/fish/functions/fish_prompt.fish
function fish_prompt set -l last_status $status if not set -q __fish_git_prompt_show_informative_status set -g __fish_git_prompt_show_informative_status 1 end if not set -q __fish_git_prompt_color_branch set -g __fish_git_prompt_color_branch brmagenta end if not set -q __fish_git_prompt_showupstream set -g __fish_git_prompt_showupstream "informative" end if not set -q __fish_git_prompt_showdirtystate set -g __fish_git_prompt_showdirtystate "yes" end if not set -q __fish_git_prompt_color_stagedstate set -g __fish_git_prompt_color_stagedstate yellow end if not set -q __fish_git_prompt_color_invalidstate set -g __fish_git_prompt_color_invalidstate red end if not set -q __fish_git_prompt_color_cleanstate set -g __fish_git_prompt_color_cleanstate brgreen end printf '%s%s %s%s%s%s ' (set_color $fish_color_host) (prompt_hostname) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal) (__fish_git_prompt) if not test $last_status -eq 0 set_color $fish_color_error end echo -n '$ ' set_color normal end
然而,fish 已经抛弃了这种方式,参见 fish-shell git。作为替代,fish 现在内置了Informative Git Prompt,该功能可以通过 fish_config
启用。
在 SSH 中用彩色显示主机名
如果需要在通过 SSH 登录到 fish 时用不同的颜色标记提示符中的主机名,可以将以下内容添加到函数 fish_prompt
中,或者添加到 fish 的配置文件中。这里以红色为例:
~/.config/fish/functions/fish_prompt.fish
... if set -q SSH_TTY set -g fish_color_host brred end ...
ssh-agent 问题
在fish中,eval (ssh-agent)
会因为变量的设置方式而报错。一个变通的方案是使用 csh 风格的选项-c
:
$ eval (ssh-agent -c)
"command not found" 事件函数
fish 包含了一个响应“命令未找到”("command not found")事件的函数 fish_command_not_found
。当遇到一个当前系统不存在的命令时,这个函数会使用 pkgfile 在官方仓库中查找哪个软件包拥有这条命令,而如果 pkgfile 不存在则回落使用 pacman -F
作为替代。
从 fish 3.2.2 开始,因为 pacman -F
严重的卡顿问题,所以 fish_command_not_found
不会再使用它作为回落。
可以写一个 fish_command_not_found
函数来替换掉 fish 自带的。比如在“命令未找到”时只打印错误消息,这样就不会有卡顿现象:
$ function fish_command_not_found __fish_default_command_not_found_handler $argv[1] end
然后保存这个函数:
$ funcsave fish_command_not_found
从 jobs 中删除进程
当退出 fish 的时候,所有后台进程也会终止。为了让一个任务即使在 fish 退出了之后也继续运行,需要先输入 disown
命令再退出。比如说,这个例子在后台起动 Firefox 然后 disown
它:
$ firefox & $ disown $ exit
这样即使退出了 fish,Firefox 也会继续运行。请查阅 fish 的 disown(1) 了解更多细节。
快速设置别名
如果想要快速设置一个持久化的别名(即使 fish 退出也不会失效),可以使用这种方法:
$ alias FooAliasName "foo --option" $ funcsave FooAliasName
而在 fish 3.0 之后的版本中,alias
增加了 --save(-s)
选项。
$ alias -s FooAliasName "foo --option"
别名会自动保存,这样就不需要再执行 funcsave
。如果想查看或者编辑所有的函数,可以运行 fish_config
,然后在网页界面的 Function 标签下进行配置。
如要获取更多文档,查阅 alias - create a function — fish-shell。
另请参阅
- https://fishshell.com/ - 主页
- https://fishshell.com/docs/current/ - 文档
- https://hyperpolyglot.org/unix-shells - Shell 语法对照表(Shell 的“罗塞塔石碑“)
- https://github.com/fish-shell/fish-shell - fish 的 GitHub 仓库