fish

出自 Arch Linux 中文维基

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[編輯 | 編輯原始碼]

本文或本章節的事實準確性存在爭議。

原因:exec fish 寫在 .bashrc 中或許不是萬全的做法,比如這個 bug 報告:https://bugzilla.redhat.com/show_bug.cgi?id=1910424.(在 Talk: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 也會繼續運行。請查閱 fishdisown(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

另請參閱[編輯 | 編輯原始碼]