> For the complete documentation index, see [llms.txt](https://handbook.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://handbook.bsdcn.org/di-3-zhang-freebsd-ji-chu/3.9.-shell.md).

# 3.9.Shell

shell 提供了用于与操作系统交互的命令行界面。Shell 从输入通道接收命令并执行它们。许多 shell 提供内建函数，用于协助日常任务，例如文件管理、文件名通配（globbing）、命令行编辑、命令宏以及环境变量。FreeBSD 提供了多个 shell，包括扩展的 POSIX® shell（[sh(1)](https://man.freebsd.org/cgi/man.cgi?query=sh\&sektion=1\&format=html)）和扩展的 C shell（[tcsh(1)](https://man.freebsd.org/cgi/man.cgi?query=tcsh\&sektion=1\&format=html)）。其他 shell 可通过 FreeBSD Ports 获得，例如 `zsh` 和 `bash`。

使用哪一个 shell 实际上是个人喜好问题。C 语言程序员可能更倾向于使用类似 C 语言的 shell，比如 [tcsh(1)](https://man.freebsd.org/cgi/man.cgi?query=tcsh\&sektion=1\&format=html)。Linux® 用户可能更喜欢 `bash`。每种 shell 都具有其独特属性，这些属性可能符合，也可能不符合用户所偏好的工作环境，因此才会有选择 shell 的自由。

一个常见的 shell 特性是文件名补全。用户输入命令或文件名前几个字母并按下 **Tab** 后，shell 会补全剩余部分。假设有两个文件分别叫做 `foobar` 和 `football`，用户要删除 `foobar`，可能会键入 `rm foo` 并按下 **Tab** 来补全文件名。

但 shell 只显示 `rm foo`，它无法补全文件名，因为 `foobar` 和 `football` 都以 `foo` 开头。如果匹配到多个名称，一些 shell 会发出哔声或显示所有可能选项。此时用户需要输入更多字符来标识所需文件名。输入一个 `t` 然后再次按下 **Tab**，shell 就能确定所需的文件名并补全剩余部分。

shell 的另一个功能是使用环境变量。环境变量是 shell 环境中存储的一组键值对。任何由 shell 启动的程序都可以读取这个环境，因此其中包含了大量程序配置。[常见环境变量](/di-3-zhang-freebsd-ji-chu/3.9.-shell.md) 提供了常见环境变量及其含义的列表。请注意，环境变量名总是大写的。

常见环境变量表：

| 变量         | 介绍                        |
| ---------- | ------------------------- |
| `USER`     | 当前登录用户的用户名。               |
| `PATH`     | 用冒号分隔的目录列表，用于查找可执行文件。     |
| `DISPLAY`  | 要连接的 Xorg 显示器的网络名称（如果可用）。 |
| `SHELL`    | 当前使用的 shell。              |
| `TERM`     | 用户终端类型的名称。用于判断终端的功能。      |
| `TERMCAP`  | 包含终端转义码的数据库项，用于执行各种终端功能。  |
| `OSTYPE`   | 操作系统类型。                   |
| `MACHTYPE` | 系统的 CPU 架构。               |
| `EDITOR`   | 用户首选的文本编辑器。               |
| `PAGER`    | 用户首选的分页查看工具。              |
| `MANPATH`  | 用冒号分隔的目录列表，用于查找手册页。       |

不同的 shell 设置环境变量的方式不同。在 [tcsh(1)](https://man.freebsd.org/cgi/man.cgi?query=tcsh\&sektion=1\&format=html) 和 [csh(1)](https://man.freebsd.org/cgi/man.cgi?query=csh\&sektion=1\&format=html) 中，使用 `setenv` 来设置环境变量。在 [sh(1)](https://man.freebsd.org/cgi/man.cgi?query=sh\&sektion=1\&format=html) 和 `bash` 中，使用 `export` 设置当前环境变量。以下是在 [tcsh(1)](https://man.freebsd.org/cgi/man.cgi?query=tcsh\&sektion=1\&format=html) 中设置默认 `EDITOR` 为 **/usr/local/bin/emacs** 的示例：

```sh
% setenv EDITOR /usr/local/bin/emacs
```

在 `bash` 中对应的命令是：

```sh
% export EDITOR="/usr/local/bin/emacs"
```

要展开环境变量以查看其当前值，在命令行的变量名前加上 `$` 符号。例如，`echo $TERM` 会显示当前的 `$TERM` 设置。

Shell 会将一些特殊字符（称为元字符）视为数据的特殊表示方式。最常见的元字符是 `*`，它代表任意数量的字符。元字符可用于执行文件名通配。例如，`echo *` 等同于 `ls`，因为 shell 会将所有匹配 `*` 的文件传递给 `echo`，并在命令行上列出它们。

为了防止 shell 解释某个特殊字符，可以用反斜杠（`\`）对其进行转义。例如，`echo $TERM` 会打印终端设置，而 `echo \$TERM` 则会原样打印字符串 `$TERM`。

## 3.9.1. 更改 Shell

永久更改默认 shell 的最简单方法是使用 `chsh`。运行此命令会打开由 `EDITOR` 环境变量配置的编辑器，默认情况下为 [vi(1)](https://man.freebsd.org/cgi/man.cgi?query=vi\&sektion=1\&format=html)。将 `Shell:` 行更改为新 shell 的完整路径。

也可以使用 `chsh -s`，该命令会在不打开编辑器的情况下设置指定的 shell。例如，将 shell 更改为 `bash`：

```sh
% chsh -s /usr/local/bin/bash
```

在提示符下输入你的密码并按下 **Return** 即可更改你的 shell。注销并重新登录后即可开始使用新 shell。

> **注意**
>
> 新的 shell *必须* 存在于 **/etc/shells** 中。如果该 shell 是按照 [安装应用程序：软件包和 Ports](/di-4-zhang-an-zhuang-ying-yong-cheng-xu-ruan-jian-bao-he-ports/4.1.-gai-shu.md) 中所述从 FreeBSD Ports 安装的，它应该会自动添加到该文件中。如果缺失，可使用以下命令添加，将路径替换为该 shell 的路径：

```sh
# echo /usr/local/bin/bash >> /etc/shells
```

然后重新运行 [chsh(1)](https://man.freebsd.org/cgi/man.cgi?query=chsh\&sektion=1\&format=html)。

## 3.9.2. 高级 Shell 技巧

UNIX® shell 不仅是个命令解释器，它还是款强大的工具，能让用户执行命令、重定向其输出、重定向其输入，并将多个命令组合在一起以优化最终输出。将这些功能与内建命令结合使用，可以为用户提供一个极具效率的环境。

Shell 重定向是将命令的输出或输入发送到另一个命令或文件中的操作。例如，将 [ls(1)](https://man.freebsd.org/cgi/man.cgi?query=ls\&sektion=1\&format=html) 命令的输出捕获到一个文件中，可以这样重定向输出：

```sh
% ls > directory_listing.txt
```

此时目录内容会列出并保存到 `directory_listing.txt` 中。有些命令可以读取输入，比如 [sort(1)](https://man.freebsd.org/cgi/man.cgi?query=sort\&sektion=1\&format=html)。要对该列表排序，可以这样重定向输入：

```sh
% sort < directory_listing.txt
```

输入会排序并显示在屏幕上。要将该输入重定向到另一个文件，可以通过混合方向来重定向 [sort(1)](https://man.freebsd.org/cgi/man.cgi?query=sort\&sektion=1\&format=html) 的输出：

```sh
% sort < directory_listing.txt > sorted.txt
```

在上述所有示例中，命令通过文件描述符重定向。每个 UNIX® 系统都有文件描述符，包括标准输入（stdin）、标准输出（stdout）和标准错误（stderr）。每种描述符都有其用途，例如输入可以是键盘或鼠标，用于提供输入；输出可以是屏幕或打印机中的纸张；错误则用于诊断或错误信息。这三者都被视为基于 I/O 的文件描述符，有时也被称为流（streams）。

通过使用这些描述符，shell 能将输出和输入在多个命令之间传递，并重定向到文件或从文件中读取。另一种重定向方法是管道操作符。

UNIX® 的管道操作符 `|` 能将一个命令的输出直接传递或重定向到另一个程序。简单来说，管道能让一个命令的标准输出作为标准输入传递给另一个命令，例如：

```sh
% cat directory_listing.txt | sort | less
```

在此示例中，`directory_listing.txt` 的内容将排序，然后输出传递给 [less(1)](https://man.freebsd.org/cgi/man.cgi?query=less\&sektion=1\&format=html)。这使用户可以按自己的节奏浏览输出内容，防止其在屏幕上滚动消失。
