fish
fish,friendly interactive shell(友好交互式 shell),是一个旨在交互和用户友好的命令行 shell。
fish 故意不完全符合 POSIX 标准,它旨在通过简化或不同的语法来解决(由创建者认为)POSIX 不一致的问题。这意味着即使是简单的 POSIX 兼容脚本也可能需要进行一些重要的改编,甚至完全重写才能在 fish 中运行。
安装
安装 fish 包。
安装完成后,只需键入 fish 即可进入 fish shell。
可以通过在 fish 中键入 help 来查找文档;它将在网页浏览器中打开。建议至少阅读“语法概述”部分,因为 fish 的语法与许多其他 shell 不同。
系统集成
必须决定 fish 是将成为用户的默认 shell,这意味着用户登录时直接进入 fish,还是在交互式终端模式下将其用作当前默认 shell 的子进程。这里我们将假设后者是Bash。关于这两种设置的详细说明:
- 将 fish 用作默认 shell:此模式需要对 fish 的工作方式及其脚本语言有一定的基本了解。用户的当前初始化脚本和环境变量需要迁移到新的 fish 环境。要在此模式下配置系统,请遵循#将 fish 设置为默认 shell。
- 将 fish 用作交互式 shell 仅:这是破坏性最小的模式,所有 Bash 初始化脚本正常运行,fish 在 Bash 之上以交互模式运行,连接到终端。要在此模式下设置 fish,请遵循#仅将 fish 设置为交互式 shell。
将 fish 设置为默认 shell
如果您决定将 fish 设置为用户的默认 shell,第一步是将该特定用户的 shell 设置为 /usr/bin/fish。这可以通过遵循命令行 shell#更改您的默认 shell中的说明来完成。
下一步是将各种 Bash 初始化脚本(即 /etc/profile、~/.bash_profile、/etc/bash.bashrc 和 ~/.bashrc)中执行的当前所需操作和配置移植到 fish 框架中。
特别是,一旦直接在 fish 下登录,$PATH 环境变量的内容应根据需要进行检查和调整。在 fish 中,$PATH 被定义为全局环境变量:它在所有函数中具有全局作用域,在重启后会丢失,并且它是一个环境变量,这意味着它会被导出到子进程。将其他位置添加到路径的推荐方法是通过从 config.fish 调用 fish_add_path 命令。例如:
$ fish_add_path -p /first/path /second/path /third/one
这三个位置将被添加到路径的开头。
仅将 fish 设置为交互式 shell
不将 fish 设置为系统范围或用户默认 shell,可以允许当前的 Bash 脚本在启动时运行。它确保当前用户的环境变量不变,并导出到 fish,然后 fish 作为 Bash 子进程运行。以下是多种在不将其设置为默认 shell 的情况下运行 fish 交互模式的方法。
修改 .bashrc 以进入 fish
将默认 shell 保持为 Bash,只需将行 exec fish 添加到适当的Bash#配置文件,例如 .bashrc。这将允许 Bash 正确 source /etc/profile 以及 /etc/profile.d 中的所有文件。因为 fish 会替换 Bash 进程,所以退出 fish 也会退出终端。与以下选项相比,这是最通用的解决方案,因为它在本地机器和 SSH 服务器上都有效。
- 在此设置中,使用
bash --norc手动进入 Bash,而不执行~/.bashrc中的命令(这会运行exec fish并重新进入 fish)。 - 为了让
bash -c 'echo test'等命令在 Bash 中运行而不是启动 fish,您可以改为写入if [ -z "$BASH_EXECUTION_STRING" ]; then exec fish; fi。 - 为了让 fish 知道它是否是一个登录 shell,您可以在
~/.bashrc中检测登录 shell 状态,并将--login选项传递给 fish。fish shell 命令status可用于显示状态。 - 仅在父进程不是 fish 时才进入 fish。这允许通过调用
bash命令快速进入 bash,而不会丢失~/.bashrc配置。
if [[ $(ps --no-header --pid=$PPID --format=comm) != "fish" && -z ${BASH_EXECUTION_STRING} && ${SHLVL} == 1 ]]
then
shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=''
exec fish $LOGIN_OPTION
fi
使用终端模拟器选项
另一种选择是使用命令行选项打开终端模拟器来执行 fish。对于大多数终端,这是 -e 开关,所以例如,要使用 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。
配置
配置文件在每次登录时运行,并位于 ~/.config/fish/config.fish。将命令或函数添加到该文件将在打开终端时执行/定义它们,类似于 .bashrc。请注意,每当需要保留变量时,都应将其设置为通用,而不是在上述配置文件中定义。
用户函数位于目录 ~/.config/fish/functions 下,文件名为 function_name.fish。
Web 界面
fish 终端颜色、提示符、函数、变量、历史记录、绑定和缩写可以通过交互式 Web 界面设置。
fish_config
如果 IPv6 已禁用,它可能无法启动。请参阅 [1] 和 IPv6#禁用 IPv6。
命令补全
fish 可以从 man pages 生成自动补全。补全写入 ~/.cache/fish/generated_completions(由 XDG_CACHE_HOME 环境变量控制),并且可以通过调用以下命令生成:
fish_update_completions
您还可以在 ~/.config/fish/completions/ 中定义自己的补全。请参阅 /usr/share/fish/completions/ 中的一些示例。
fish 内置了对 Arch Linux 特定命令(如 pacman、pacman-key、makepkg、pbget、pacmatic)的上下文感知补全,因为 fish 开发的策略是包含所有存在的补全到上游 tarball 中。内存管理足够智能,可以避免对资源产生任何负面影响。
技巧与提示
命令替换
fish 不实现 Bash 风格的历史替换(例如 sudo !!),并且开发人员在 fish faq 中建议使用交互式历史记录召回界面:向上箭头召回整个过去的行,Alt+向上箭头(或Alt+.)召回单个参数,而Alt+s在现有行前面加上sudo。
但是,一些解决方法描述在 fish wiki 中:虽然不提供完整的历史替换,但一些函数将!!替换为前一个命令或!$替换为前一个最后一个参数。
禁用问候语
默认情况下,fish 在启动时会打印一条问候消息。要禁用它,请运行一次:
$ set -U fish_greeting
这将清除与所有 fish 实例共享的通用 fish_greeting 变量,该变量在 shell 重启后保留。
使 su 启动 fish
如果 su 因 Bash 是目标用户(如果没有提供用户名,则为root)的默认 shell 而以 Bash 启动,则可以定义一个函数来将其重定向到 fish,无论用户的 shell 是什么。
~/.config/fish/functions/su.fish
function su command su --shell=/usr/bin/fish $argv end
登录时启动 X
将以下内容添加到您的 ~/.config/fish/config.fish 的底部。
# Start X at login
if status is-login
if test -z "$DISPLAY" -a "$XDG_VTNR" = 1
exec startx -- -keeptty
end
end
对于那些以交互模式运行 fish 的用户,请将上面的代码中的 status is-login 替换为 status is-interactive。
在提示符中显示 git 状态
如果您希望 fish 在 git 目录中显示分支和脏状态,您可以定义以下 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
在 SSH 提示符中着色主机名
要在通过 SSH 连接时动态地为提示符中的主机名着色,请将以下行添加到 fish_prompt 函数或 fish 配置文件中,这里使用红色:
~/.config/fish/functions/fish_prompt.fish
... if set -q SSH_TTY set -g fish_color_host brred end ...
请注意,默认的 fish 提示符会在通过 SSH 连接时将主机名染成黄色;此功能不需要对提示符进行其他修改。
评估 ssh-agent
在 fish 中,eval (ssh-agent) 会因变量设置方式而产生错误。要解决此问题,请使用 csh 风格的 -c 选项:
$ eval (ssh-agent -c)
评估 keychain
因为 keychain --eval 使用 SHELL 环境变量来格式化输出,所以它应该能与 fish 作为默认 shell 一起使用。但是,如果仅将 fish 用作交互式 shell,则必须设置此变量:
$ SHELL=/bin/fish keychain --eval --quiet -Q id_ed25519 | source
“命令未找到”钩子
Fish 包含一个“命令未找到”钩子,当输入未识别的命令时,它会自动搜索官方存储库。此钩子将使用 pkgfile 运行,如果未安装,则回退到 pacman -F。
自 3.2.2 起,“命令未找到”将不再默认回退到 pacman -F,因为其性能不佳。
如果这种行为引入的延迟不希望出现,可以通过重新定义 fish_command_not_found 来覆盖此钩子,使其仅打印错误消息:
$ function fish_command_not_found
__fish_default_command_not_found_handler $argv[1]
end
要使此更改永久化,可以使用内置函数 funcsave。
$ funcsave fish_command_not_found
从作业列表中移除进程
fish 会终止在 fish 终止时放入后台的任何作业。要使作业在 fish 终止后继续运行,请先使用 disown 内置命令。例如,以下命令在后台启动 firefox,然后将其 disown:
$ firefox & $ disown
这意味着当 fish 进程关闭时,firefox 不会关闭。有关更多详细信息,请参阅 fish 中的 disown(1)。
设置持久化别名
要快速创建持久化别名,可以使用此示例中显示的方法:
$ alias lsl "ls -l" $ funcsave lsl
从 fish 版本 3.0 开始,alias 支持 -s/--save 选项。
$ alias -s lsl "ls -l"
这将创建函数:
function lsl
ls -l $argv
end
并将别名设置为持久化 shell 函数。要查看所有函数和/或编辑它们,只需使用 fish_config 并在 Web 配置页面的“函数”选项卡中查找。
有关更详细的信息,请参阅 alias - create a function — fish-shell。
登录时 source /etc/profile
与 bash 不同,fish 在 tty 登录时不会 source /etc/profile。如果您需要 source 此文件以获取 /etc/profile.d 目录中附加和声明的环境变量,您可以将以下内容添加到您的配置中:
~/.config/fish/config.fish
# source /etc/profile with bash
if status is-login
if not set -q __sourced_profile
set -x __sourced_profile 1
exec bash -c "\
test -e /etc/profile && source /etc/profile
test -e $HOME/.bash_profile && source $HOME/.bash_profile
exec fish --login
"
end
# put your other configs below
#
set -e __sourced_profile
end
这允许您将 fish 作为登录 shell 运行,同时仍拥有通常在 bash 登录会话中拥有的所有环境变量。
参见
- https://fishshell.com/ - 主页
- https://fishshell.com/docs/current/ - 文档
- https://hyperpolyglot.org/unix-shells - Shell 语法对应表(“shell 罗塞塔”)
- https://github.com/fish-shell/fish-shell - fish 在 GitHub 上