fish
fish,friendly 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 特定命令(如 pacman、pacman-key、makepkg、pbget、pacmatic)的上下文感知补全,因为 fish 开发的策略是将所有现有的补全都包含在上游 tarball 中。内存管理非常智能,可以避免对资源产生任何负面影响。
技巧与提示
命令替换
fish 不实现 Bash 风格的历史记录替换(例如 sudo !!
),并且开发人员在 fish faq 中建议改用交互式历史记录调用界面:Up
箭头调用整个过去的行,Alt+Up
(或 Alt+.
)调用单个参数,而 Alt+s
将 sudo
添加到现有行的前面。
但是,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
登录会话中拥有的所有环境变量。
参见
- https://fishshell.com/ - 首页
- https://fishshell.com/docs/current/ - 文档
- https://hyperpolyglot.org/unix-shells - Shell 语法对应表(“shell rosetta”)
- https://github.com/fish-shell/fish-shell - GitHub 上的 fish