Fish

Fish (消歧義)
fish (friendly interactive shell) 是一個Unix shell。fish旨在成為一個比其他shell交互性更強、用戶體驗更好的shell，並讓其豐富的強大功能能夠被用戶輕鬆發現、記住並學以致用。fish的語法既不衍生於Bourne shell也不衍生於C Shell，故被分類為一種“外來”shell。有別於為節約系統資源而默認禁用部分功能的其他shell，fish的全部功能都是默認啟用的。

**特色**
fish能根據用戶的輸入歷史與當前所在的目錄提供即時的自動完成。與bash的類似功能R歷史搜索相比，這種不必頻繁切換模式還可以用方向鍵選擇建議項的做法使用戶能更流暢地進行輸入。
fish也擁有功能豐富的Tab補全功能。fish能夠自動補全文件路徑、變量與不少命令的參數，且支持路徑通配符與C shell的花括號展開。fish某種意義上會通過分析命令的man文檔生成與之相關的補全。
fish傾向於使用命令來代替語法結構。由於命令相比語法結構能更方便地在shell內查到幫助內容，fish的功能很容易在使用過程中被用戶自行發現。fish允許子程序提供對自己的說明，進一步免去了來回查找幫助的麻煩。fish還允許用戶在擁有圖形用戶界面的瀏覽器內查看幫助。

**語法**
fish的語法類似於其他兼容POSIX的shell，但由於其開發者認為POSIX shell設計得有問題，fish的語法又與POSIX shell有相當的不同。
# 下面演示將"bar"賦給變量foo的過程。
# 由於等號在其他shell中會根據兩端是否有空格而表現出不同的行為，
# fish選擇了不在賦值中使用這個令人困惑的符號。
# set命令也可以用於數組，並可以輕鬆設置變量的作用域。
> set foo bar
> echo $foo
bar
# 下面演示使用命令替換將pwd的輸出賦給wd的過程。
# 由於重音符（`）視覺上容易與單引號混淆且左右的符號都相同的話難以嵌套，
# fish改為在命令替換中使用括號。
# 但與ksh不同的是，fish僅在變量展開中使用美元符號。
> set wd (pwd)
> echo $wd
~
# 將一個有五個元素的數組賦給A。
> set A 3 5 7 9 12
# 將A的第二個和第一個元素賦給B。
# fish的數組索引從1開始。
> set B $A2 1
> echo $B
5 3
# 可以用命令替換索引數組中的元素……
> seq 3
1
2
3
> echo $A(seq 3)
3 5 7
# ……也可以用其他數組來索引。
# 下面將從A中刪除第五個與第三個元素。
> set --erase A$B
> echo $A
3 5 9
# for循環。
> for i in *.jpg
convert $i (basename $i .jpg).png
end
# 分號可以代替換行來標記語句的結束：
> for i in *.jpg; convert $i (basename $i .jpg).png; end
# 但由於fish也會在歷史記錄中分開記錄每一行，使用換行一般更加方便。

# while循環。
# 下面演示輸出/etc/passwd中每行的第五個字段。
> cat /etc/passwd | while read line
set arr (echo $line|tr : \n)
echo $arr5
end

**沒有子shell**
其他shell的部分語法結構，例如管道、子程序與循環，是使用一種稱為子shell的方式實現的。所謂子shell即臨時執行一個用完即退出的新的子進程。在子shell中執行的修改通常不符合一般人的直覺地，不會反映到真正的shell上（即沒有函數副作用）。fish不依賴於子shell實現其語法結構，故所有內置命令在任何語境下都是會正常運作的。
# 相當多的shell會將read在單獨的子shell中執行，所以如下語句在他們中無法按預期工作。
# 在常見shell中，bash的管道右邊無法產生副作用，故line並不會被賦值；
# ksh中line會被正確賦值，但管道左邊的語句無法產生副作用；
# 但是fish和zsh一樣，允許管道兩邊都能有副作用。
> cat *.txt | read line
例如，下述bash腳本會因為子shell而導致循環內部給found賦的值在退出循環後即消失
found=
cat /etc/fstab | while read dev mnt rest; do
if test "$mnt" = "/"; then
found="$dev"
fi
done
而需要用另一種方式來規避這個問題：
found=
while read dev mnt rest; do
if test "$mnt" = "/"; then
found="$dev"
fi
done 如下的fish腳本則無需擔心子shell會影響副作用。
set found 
cat /etc/fstab | while read dev mnt rest
if test "$mnt" = "/"
set found $dev
end
end

**有用的錯誤信息**
fish會在發生錯誤時清晰地指出出錯的位置並給出修正的方法。
> foo=bar
fish: Unknown command “foo=bar”. Did you mean “set VARIABLE VALUE”?
For information on setting variable values, see the help section on
the set command by typing “help set”.
# fish：未知的命令"foo=bar"。你是想輸入"set 變量 值"嗎？
# 關於如何設置變量的值，請輸入"help set"獲取set命令的幫助。
> echo ${foo}bar
fish: Did you mean {$VARIABLE}? The '$' character begins a variable
name. A bracket, which directly followed a '$', is not allowed as a
part of a variable name, and variable names may not be zero characters
long. To learn more about variable expansion in fish, type “help
expand-variable”.
# fish：你是想輸入{$變量}嗎？美元符號"$"僅用於變量名開頭，而美元符號後的
# 那個花括號並不能作為變量名稱的一部分，且變量也不能沒有名稱。
# 關於如何展開變量，請輸入"help expand-variable"。
> echo $(pwd)
fish: Did you mean (COMMAND)? In fish, the '$' character is only used
for accessing variables. To learn more about command substitution in
fish, type “help expand-command-substitution”.
# fish: 你是想輸入(命令)嗎？在fish中，美元符號"$"僅用於訪問變量。
# 關於如何進行命令替換，請輸入"help expand-command-substitution"。

**通用變量**
Fish有一個名為通用變量的功能。通過利用通用變量，用戶可以在多個同時運行的fish實例之間共享一個變量。即使用戶註銷或者計算機重啟，通用變量的值也不會丟失。
# 將emacs設置為默認文本編輯器。
# "--universal"或者"-U"表示設置通用變量。
> set --universal EDITOR emacs
# 如下命令會把fish的提示符中的當前目錄變成藍色。
# 不止執行命令的這個fish，現在所有正在運行的fish的提示符都會發生變化。
> set --universal fish_color_cwd blue

**其它功能**
 高級tab補全- 帶完備的錯誤檢查的語法高亮- 支持X Window系統的剪貼板- 基於terminfo的智能終端處理- 可搜索的命令行歷史記錄
第二版還加入瞭如下功能：- 自動補全- 支持256色- 基於網頁的配置功能- 能夠提升性能的更多的內置命令

**參考**

**另請參閱**
 Unix shell
*Comparison of command shells

**外部鏈接**
  項目主頁date=20090219001811 
*GitHub上的 fishdate=20181220120639 倉庫
*Gitorious上的 fish倉庫（不再使用）
*SourceForge上的 fishdate=20090705111449 倉庫（不再使用）- Fish-usersdate=20160308065537  - fish用戶的綜合討論列表- bash到fish的命令翻譯對照date=20190216030401