跳过导览列.
首页
做最好的Linux技术文档网站

对话 UNIX: 使用 fish!

Friendly Interactive Shell(fish)很容易使用。它的语法、上下文相关的帮助和颜色编码的命令行界面(CLI)显著简化了 UNIX® 的使用,减轻了脚本编程的负担。

英语是一种令人困惑的语言。例如,请考虑 moon 和 good 这两个单词。对外行人而言,这两个单词似乎应该是押韵的,但是前者的读音是 /mun/(根据 International Pronunciation Alphabet),而后者的读音是 /good/。似乎英语中的惟一规则就是例外。

UNIX shell 同样令人困惑。例如,在 Bourne shell(和大多数常用的 UNIX shell)中,'$var'"$var" 和 `$var` 看起来相似,但是它们会产生很不一样的结果。(在本文中的 shell 示例中,每个 CLI 前面都加上使用的 shell 的名称和命令编号) 。

bash-1) # Demonstrate the differences between single-, double-, and back quotes
bash-2) var=ls
bash-3) echo '$var'
$var
bash-4) echo "$var" 
ls
bash-5) echo `$var`
Rakefile app bin components config db
    doc lib log patches public script src
    test tmp vendor

在上面的命令序列中,把变量 var 设置为两字母的字符串 ls。在第一个 echo 命令中,单引号禁止解释此变量,因此会按原样显示引号中的文本,即四字母的字符串 $var。在第 4 行代码中,双引号会解释此变量,所以结果是字符串 ls。最后,反撇号解释变量并作为子 shell 运行中间结果。因此,`$var` 产生中间字符串 ls,它作为 shell 命令运行,生成当前目录的内容列表。

当然,这三种操作符(单引号、双引号和反撇号)都有合法的用途,但是与英语中的例外一样,记住和掌握这些细微差异很令人头疼。为了进一步证明这一点,请问:$var 和 "$var" 之间有什么差异?(提示:假设 $var 包含空格。)

bash-1) # Create three files and try to remove two
bash-2) touch three two one
bash-3) var="one two"
bash-4) rm "$var"
rm: one two: No such file or directory
bash-5) rm $var
bash-6) ls
three

如果一个变量包含空格,双引号会按原样把变量展开为一个 参数。否则,变量中的任何空格都被解释为参数分隔符。

shell 语法很令人头疼。这很糟糕,因为它使 CLI(UNIX 最强大的特性之一)更难掌握。上面这样的不一致问题甚至会给 UNIX 老手带来困扰。

好在,fish (Friendly Interactive Shell) 的出现改变了这种混乱局面,它提供简明的语法,显著改善了用户体验。与其他 shell 一样,fish 也提供重定向、快捷方式、globbing(即通配符的展开)、子 shell、制表符补全和变量。但是,与其他 shell 不同,fish 还提供颜色编码的 CLI、功能丰富的命令行编辑器和大量文档。

另外,对于执行任何操作,fish 只提供一种方式,这非常明智。如果一个 UNIX 实用程序能够完成某一任务,fish 就不会通过内置命令重复提供此特性。例如,fish 使用系统范围的应用程序 /bin/kill 终止进程。(与之相反,Bourne shell 通过一个内置应用程序实现了它自己的 kill 版本。可以在 Bourne shell 命令提示上输入 /bin/kill 来访问此版本)。fish 尽可能优先考虑简单性而不是灵活性,这显著简化了它的使用方法。

下面,我们来安装 fish 并体验它的一些特性。

获取 fish

fish 是由 Axel Liljencrantz 创建的一个开放源码项目,采用的许可协议是 GNU General Public License, version 2。到编写本文时,fish 的最新版本是 1.23.0,此版本于 2008 年 1 月 13 日发布。

如果使用 UNIX 或 UNIX 类系统(比如 Linux® 或 Mac OS X),那么应该很容易在您的系统上从源代码构建 fish。下面是构建步骤,见 清单 1

  1. 下载程序的最新源代码压缩包。
  2. 解压。
  3. 进入源代码目录。
  4. 配置构建。
  5. 运行 make

清单 1. 从源代码构建 fish

				
bash-1) wget http://www.fishshell.org/files/1.23.0/fish-1.23.0.tar.gz
bash-2) tar xzvf fish-1.23.0.tar.gz
bash-3) cd fish-1.23.0
bash-4) ./configure --without-xsel
checking if autoconf needs to be run... no
checking if autoheader needs to be run... no
checking for /usr/pkg/include include directory... no
...
bash-5) make
gcc -c -o function.o function.c
...
bash-6) sudo make install
...
To use fish as your login shell:
* add the line '/usr/bin/fish' to the file '/etc/shells'.
* use the command 'chsh -s /usr/bin/fish'.

如果使用 UNIX 类系统,configure 可能不需要更多的标志。但是,为了尽可能减少依赖性并让 fish 采用与常用 shell 相同的目录结构,可以分别添加 --without-xsel 和 --prefix=/usr。(如果使用 Mac OS X version 10.4 Leopard,那么还要添加参数 LDFLAGS=-liconv。如果在 Mac OS X 上省略后一个选项,那么无法编译附带的 fish 实用程序) 。

另外,如果使用流行的 UNIX 版本,很可能会找到预先构建好的二进制版本,可以把它直接安装在您的系统上。例如,如果使用 Debian Linux,那么可以用 sudo apt-get install fish 命令直接安装 fish。请访问 fish 项目的主页,了解是否有针对您的系统的二进制版本。


回页首

入门

在讨论比较复杂的主题之前,我们先看看在 fish 中如何完成一些常见的 shell 任务:

  • 要想重定向标准输入和标准输出,应该分别使用操作符 < 和 >。要想重定向标准错误,应该使用 ^ 操作符,见 图 1。使用 ^^ 把标准错误追加到一个文件中。 

    图 1. 用 ^ 操作符重定向标准错误
    用 ^ 操作符重定向标准错误

    在命令 3 中,rm 产生的错误消息被重定向到 errors 文件中。命令 4 显示此文件的内容。fish shell 为重定向提供各种支持,比如把描述符组合成一个流和结束描述符。

    顺便说一句,文本的颜色和下划线不是编辑出来的。shell 会在您输入时在 CLI 中突出显示文本。绿色表示命令名是有效的;无效的命令名用红色表示。下划线表示指定的文件存在。(后面一节详细讨论 shell 的反馈)。

  • 使用圆括号(())运行子 shell,见 图 2。圆括号中的文本被解释为一系列命令,shell 会把它们替换为执行结果。 

    图 2. 使用圆括号运行子 shell
    使用圆括号运行子 shell

  • 通过创建 fish 函数创建别名(即快捷方式)。

    函数可以包含一个或多个命令,特殊变量 $argv 会自动展开成命令行上传递的参数列表。

    可以用 functions 命令列出已定义的所有函数。使用 functions --erase name 删除函数,例如 functions --erase ll

    还可以立即保存在命令行上编写的任何函数。在编写完代码时,输入 funcsave name,例如 funcsave ll。在此之后,当前运行的所有 shell 和以后的所有 shell 都可以使用此函数。可以使用 funced name 命令以交互方式编辑现有的函数。funced 命令提供语法突出显示、制表符补全和自动缩进;funcsave 和 funced 使用户能够更方便地定制 shell。

  • 输入 set variable name value 来设置变量。与内置命令 functions 一样,输入 set --erase variable name 就可以删除一个变量。输入美元符号($)和变量名,就可以获取变量中存储的值,见 图 3。 

    图 3. 检查一个变量是否存在
    检查一个变量是否存在

    fish 提供 --query 选项来检查是否定义了一个变量。如果已经设置了此变量,set --query 返回状态码 0,这表示没有出现错误;否则,返回 1。语句 6 用 or 操作符连接两个命令:第二个命令(echo)只在第一个命令失败的情况下执行。

那么,fish 如何处理 $var'$var'"$var" 和 `$var` 呢?它遵守几条简单的规则:

我们来看看这些规则的实际应用。

命令 1 创建四个 文件,最后一个文件的名称包含空格。命令 3 和 4 删除 file 变量指定的文件。命令 6 和 7 删除 twofiles 变量指定的两个文件。仔细看一下命令 6:因为值没有放在引号(单引号或双引号)中,所以不保留空格。因此,命令 7 把此变量展开成两个参数并删除两个文件。命令 9 和 10 重复命令 6 和 7 中的场景。

命令 11 和 12 演示空格规则。尽管在命令 12 中变量没有放在双引号中,但是 fish 在命令 11 中保留空格。非常好

命令 14 到 16 演示 fish 的嵌套引号规则。现在,再看一下命令 11、15 和 16。shell 使用颜色编码显示匹配的引号,以此确保语法正确。再看一下命令 9 和 11。后一个命令在文件名上显示下划线,这表示此文件存在。在命令 9 中没有下划线,这提示用户某些地方出错了。

fish 的首字母代表 Friendly,对用户友好是它的主要目标。


回页首

对于新手非常有帮助的一个特性

说到对用户友好,就不能不提到 fish制表符补全 特性,这个新颖的特性对于 UNIX 新用户和专家都极其有帮助。为了体验制表符补全,请按下面的示例操作。在每行的末尾按 Tab 键。

如果您不确定一个命令名的拼写,可以在输入几个字母之后按 Tab,就会看到可能的完整命令的列表,见 图 5。(在您的系统上显示的命令列表可能与这里显示的不一样。此列表取决于 PATH 环境变量和您的 UNIX 系统的内容) 。

图 5. 按 Tab 补全命令名
按 Tab 补全命令名

注意 CLI 中的红色文本。如果 fish 不认识一个命令名,就用红色显示它。按 Tab,就会显示以目前输入的字母开头的所有应用程序名(以及简短的描述)。在空提示行上按 Tab,就会看到 PATH 中的所有应用程序。

如果想了解一个命令的可用选项,那么在连字符(-)或双连字符(--)后面按 Tab,见 图 6

图 6. 还可以通过按 Tab 补全一个选项
还可以通过按 Tab 补全一个选项

此时,fish 会显示可用的选项。shell 维护许多常用命令和选项的索引,您很可能能够得到所需的帮助。但是,定制的或更复杂的实用程序可能缺少这种数据。可以阅读 fish 文档,了解关于编写自己的补全特性的更多信息。

还可以在输入选项的几个字母之后按 Tab,见 图 7。shell 会显示所有匹配的选项。

图 7. 还可以输入选项的一部分
还可以输入选项的一部分

如果您不知道一个命令处理的操作数类型,fish 在许多情况下可以提供帮助,但并不是在所有情况下都可以。例如,如果输入 set(或 vared,即 fish 变量编辑器)和一个空格,然后按 Tab,fish 会显示可用变量的列表。set 的操作数是一个变量。同样,如果输入 type 和一个空格,然后按 Tab,fish 会显示内置函数的列表,这些函数扩展文件系统上可用的实用程序。

在一般情况下,fish 中的所有内置函数都有上下文相关的操作数补全。请试一下 cd,见 图 8

图 8. 许多命令是上下文相关的,可以显示适当的参数
许多命令是上下文相关的,可以显示适当的参数

cd 函数是一个 fish 函数,它的操作数是一个现有的目录。在输入 cd 之后按 Tabfish 会显示 CDPATH 中的每个目录包含的所有现有目录。

另一个智能化补全与 ssh 相关。输入 ssh 和一个空格,然后按 Tab,就会看到从 Secure Shell 已知主机文件(通常在 ~/.ssh/known_hosts 中)获取的已知主机名列表:

fish-1) ssh
login.example.com  (Hostname)
host1.example.com         (Hostname)

fish shell 还会补全文件名和目录名。同样,它会在您输入路径名时突出显示正确的元素。

fish 与其他 shell 之间的一个重要差异是,它不提供历史快捷方式,比如 !!! 和 !$


回页首

使用 fish 作为登录 shell

如果您喜欢 fish,希望用它作为登录 shell,那么把 fish 的路径添加到正式 shell 列表(/etc/shells)中,然后运行 chsh

bash-1) type fish
fish is /usr/bin/fish
bash-2) sudo vi /etc/shells
Add the line /usr/bin/fish to the file if it's missing, and save the file
bash-3) cat /etc/shells
/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/bin/fish
bash-4) chsh -s /usr/bin/fish
Changing shell for strike
Password: ********
bash-5) login strike
Password: ********
Last login: Wed Oct  8 15:02:21 on ttys000
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
fish-1) echo $SHELL
/usr/bin/fish

回页首

结束语

fish 中还有许多有用的特性值得研究。“fish 这条鱼非常有营养。”

可以调整语法突出显示采用的颜色。可以通过编辑 ~/.config/fish/config.fish 定制启动过程。可以使用通用变量 和 fishd 跨 shell 实例共享变量。这种 shell 还有出色的历史搜索特性、交互式变量编辑器和交互式命令行编辑器。

最好的一点是,fish 本身提供大量文档。如果需要帮助,只需在命令提示上输入 help

医生的意见是对的:吃 “鱼” 对您有益。

回应浏览选项

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Since fish is a text based

Since fish is a text based program, it is not very well suited for screenshots. But everybody loves pretty pictures, so this page tries to make the best of a bad situation.

 

This screenshot shows multiline editing in fish. Notice how fish automatically indents the code. You can move up and down in the code using the cursor keys.
This screenshot shows several types of tab completions. Note how fish provides detailed descriptions for it's completions.
This screenshot shows the tab completion pager in action. The arrow keys, the space bar and the page up/down keys move through the completion list. Hitting any other character will exit the pager and insert the character into the command line.
This screenshot shows fish flagging a misspelled option for ls. fish also flags such errors as mistyped files, command names and mismatched parenthesis.
This screenshot shows fish with colorful syntax highlighting. Note that matching parenthesis are highlighted. All colors can be configured to suit your (lack of) taste.
This screenshot shows one of the fish error messages. Fish tries to detect as many common errors as possible and offer a potential solution in the error message.

 

回应浏览选项

Select your preferred way to display the comments and click "Save settings" to activate your changes.