fish - Arch Linux 中文维基

跳至內容

# fish

出自 Arch Linux 中文维基

翻譯狀態：

- 本文（或部分內容）譯自 Fish，最近一次同步於 2024-12-16，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

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知曉其是否是一個登錄shell，您可以在 `~/.bashrc` 檢測登錄 shell 狀態，並給 fish 加上 `--login` 選項。 fish 的 shell 命令 `status` 可用於顯示狀態。
- 在父進程不是 fish 的情況下才起動 fish：這種方法可以在更方便地切換到 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`。比如，要打開 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, pbget, pacmatic 這些命令的自動補全規則已經在內置在 fish 中了，因為 fish 在開發的時候就包含了很多命令的補全規則。fish 的內存管理足夠智能，不會因為命令補全產生負面影響。

## 提示與技巧

### 命令替換

fish 沒有 Bash 式的歷史記錄替換功能（如 `sudo !!`）。fish 的開發者在 fish faq 中建議使用交互式的方式調用歷史記錄：`上`方向鍵可以按整條命令回顧歷史，而`Alt+上`可以回顧命令的單個參數。`Alt+S` 會在整條命令的最前面加上 `sudo`。

不過，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
    ...

Note that the default fish prompt colors the hostname yellow when connected through SSH; additional modification to the prompt is not required for this functionality.

### 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` 增加了 `-s`/`--save` 選項。

    $ alias -s FooAliasName "foo --option"

別名會自動保存，這樣就不需要再執行 `funcsave`。如果想查看或者編輯所有的函數，可以運行 `fish_config`，然後在網頁界面的 Function 標籤下進行配置。

如要獲取更多文檔，查閱 alias - create a function — fish-shell。

### Source /etc/profile on login

與 `bash` 不同，`fish` 在 tty 登錄時不會加載 `/etc/profile`。如果你需要加載這個文件以獲取在 `/etc/profile.d` 目錄中追加和聲明的環境變量，可以將以下內容添加到你的配置文件中：

    ~/.config/fish/config.fish

    # 使用 bash 加載 /etc/profile
    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 的「羅塞塔石碑「）
- https://github.com/fish-shell/fish-shell - fish 的 GitHub 倉庫

分類：​

- 命令行解釋器

fish
新增話題