fish (英語:friendly interactive shell) 是一個Unix shell。fish旨在成為一個比其他shell互動性更強、使用者體驗更好的shell,並讓其豐富的強大功能能夠被使用者輕鬆發現、記住並學以致用。fish的語法既不衍生於Bourne shell也不衍生於C Shell,故被分類為一種「外來」shell。有別於為節約系統資源而預設禁用部分功能的其他shell,fish的全部功能都是預設啟用的。
此條目或其章節極大或完全地依賴於某個單一的來源。 (2019年6月13日) |
此條目過於依賴第一手來源。 (2019年6月13日) |
![]() | |
![]() | |
原作者 | Axel Liljencrantz |
---|---|
開發者 | fish-shell developers |
首次釋出 | 2005年2月13日 |
目前版本 |
|
原始碼庫 | |
作業系統 | Unix-like |
類型 | Unix shell |
授權條款 | GNU通用公眾授權條款 |
網站 | fishshell![]() |
特色
fish能根據使用者的輸入歷史與當前所在的目錄提供即時的自動完成。與bash的類似功能Ctrl+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 $A[2 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 $arr[5]
end
其他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 < /etc/fstab
如下的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
其它功能
第二版還加入了如下功能:
- 自動補全
- 支援256色
- 基於網頁的組態功能
- 能夠提升效能的更多的內建命令