fish

出自 ArchWiki

fishfriendly interactive shell(友好的交互式 Shell),是一个旨在提供交互性和用户友好性的命令行 Shell

fish 有意不完全兼容 POSIX 标准,它的目标是通过简化或不同的语法来解决 POSIX 的不一致性(正如创建者所认为的那样)。这意味着即使是简单的 POSIX 兼容脚本也可能需要进行一些重大调整甚至完全重写才能在 fish 中运行。

安装

安装 fish 软件包。对于开发版本,请安装 fish-gitAUR 软件包。

安装完成后,只需输入 fish 即可进入 fish shell。

可以通过在 fish 中输入 help 找到文档;文档将在 Web 浏览器中打开。建议至少阅读“语法概述”部分,因为 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。这可以通过按照 Command-line 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 设置为系统范围或用户默认值允许当前的 Bash 脚本在启动时运行。它确保当前用户的环境变量保持不变,并导出到 fish,然后 fish 作为 Bash 子进程运行。以下是在不将 fish 设置为默认 shell 的情况下,在交互模式下运行 fish 的几种方法。

修改 .bashrc 以进入 fish

将默认 shell 保留为 Bash,只需将行 exec fish 添加到适当的 Bash#配置文件 中,例如 .bashrc。这将允许 Bash 正确地执行 /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 界面

可以使用交互式 Web 界面设置 fish 终端颜色、提示符、函数、变量、历史记录、绑定和缩写。

fish_config

如果 IPv6 已禁用,则可能无法启动。请参阅 [1]IPv6#禁用 IPv6

命令补全

fish 可以从 man 手册页生成自动补全。补全文件被写入 ~/.local/share/fish/generated_completions/,可以通过调用以下命令生成:

fish_update_completions

您还可以在 ~/.config/fish/completions/ 中定义自己的补全文件。有关示例,请参阅 /usr/share/fish/completions/

fish 内置了针对 Arch Linux 特定命令(如 pacmanpacman-keymakepkgpbgetpacmatic)的上下文感知补全,因为 fish 开发的策略是将所有现有的补全都包含在上游 tarball 中。内存管理非常智能,可以避免对资源产生任何负面影响。

技巧与提示

命令替换

fish 不实现 Bash 风格的历史记录替换(例如 sudo !!),并且开发人员在 fish faq 中建议改用交互式历史记录调用界面:Up 箭头调用整个过去的行,Alt+Up(或 Alt+.)调用单个参数,而 Alt+ssudo 添加到现有行的前面。

但是,fish wiki 中描述了一些解决方法:虽然不提供完整的历史记录替换,但某些函数会将 !! 替换为上一个命令,或将 !$ 替换为上一个最后一个参数。

禁用问候语

默认情况下,fish 在启动时打印问候消息。要禁用它,请运行一次:

$ set -U fish_greeting

这将清除通用变量 fish_greeting,该变量与所有 fish 实例共享,并在 shell 重启后保留。

使 su 启动 fish

如果 su 以 Bash 启动,因为 Bash 是目标用户(如果未提供用户名,则为 root)的默认 shell,则可以定义一个函数将其重定向到 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 环境变量来格式化输出,因此它应该与作为默认 shell 的 fish 一起工作。但是,如果仅将 fish 用作交互式 shell,则必须设置此变量:

$   SHELL=/bin/fish keychain --eval --quiet -Q id_ed25519 | source

“命令未找到” hook

Fish 包含一个“命令未找到” hook,当输入无法识别的命令时,它将自动搜索官方存储库。此 hook 将使用 pkgfile 运行,如果未安装,则回退到 pacman -F

自 3.2.2 版本起,“命令未找到”默认不会回退到 pacman -F,因为其 性能不佳

如果此行为引入的延迟是不可取的,则可以通过重新定义 fish_command_not_found 来覆盖此 hook,使其仅打印错误消息:

$ 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

登录时执行 /etc/profile

bash 不同,fish 在 tty 登录时不会执行 /etc/profile。如果您需要执行此文件以获取在 /etc/profile.d 目录中附加和声明的环境变量,您可以将以下内容添加到您的配置中:

~/.config/fish/config.fish
# source /etc/profile with bash
if status is-login
    exec bash -c "test -e /etc/profile && source /etc/profile;\
    exec fish"
end

这允许您将 fish 作为您的登录 shell 运行,同时仍然拥有您通常在 bash 登录会话中拥有的所有环境变量。

参见