Zsh 入门
zsh

> 
> 从 Bash 进阶到 Z-shell，改进你的 shell 体验。
> 
> 
> 


![](/data/attachment/album/201909/23/163910imr1z1qw1ruo9uqs.jpg)


Z-shell（Zsh）是一种 Bourne 式的交互式 POSIX shell，以其丰富的创新功能而著称。Z-Shell 用户经常会提及它的许多便利之处，赞誉它对效率的提高和丰富的自定义支持。


如果你刚接触 Linux 或 Unix，但你的经验足以让你可以打开终端并运行一些命令的话，那么你可能使用的就是 Bash shell。Bash 可能是最具有代表意义的自由软件 shell，部分是因为它具有的先进的功能，部分是因为它是大多数流行的 Linux 和 Unix 操作系统上的默认 shell。但是，随着使用的次数越多，你可能会开始发现一些细节可能能够做的更好。开源有一个众所周知的地方，那就是选择。所以，许多人选择从 Bash “毕业”到 Z。


### Zsh 介绍


Shell 只是操作系统的接口。交互式 shell 程序允许你通过称为*标准输入*（stdin）的某个东西键入命令，并通过*标准输出*（stdout）和*标准错误*（stderr）获取输出。有很多种 shell，如 Bash、Csh、Ksh、Tcsh、Dash 和 Zsh。每个都有其开发者所认为最适合于 Shell 的功能。而这些功能的好坏，则取决于最终用户。


Zsh 具有交互式制表符补全、自动文件搜索、支持正则表达式、用于定义命令范围的高级速记符，以及丰富的主题引擎等功能。这些功能也包含在你所熟悉的其它 Bourne 式 shell 环境中，这意味着，如果你已经了解并喜欢 Bash，那么你也会熟悉 Zsh，除此以外，它还有更多的功能。你可能会认为它是一种 Bash++。


### 安装 Zsh


用你的包管理器安装 Zsh。


在 Fedora、RHEL 和 CentOS 上：



```
$ sudo dnf install zsh
```

在 Ubuntu 和 Debian 上：



```
$ sudo apt install zsh
```

在 MacOS 上你可以使用 MacPorts 安装它：



```
$ sudo port install zsh
```

或使用 Homebrew：



```
$ brew install zsh
```

在 Windows 上也可以运行 Zsh，但是只能在 Linux 层或类似 Linux 的层之上运行，例如 [Windows 的 Linux 子系统](https://devblogs.microsoft.com/commandline/category/bash-on-ubuntu-on-windows/)（WSL）或 [Cygwin](https://www.cygwin.com/)。这类安装超出了本文的范围，因此请参考微软的文档。


### 设置 Zsh


Zsh 不是终端模拟器。它是在终端仿真器中运行的 shell。因此，要启动 Zsh，必须首先启动一个终端窗口，例如 GNOME Terminal、Konsole、Terminal、iTerm2、rxvt 或你喜欢的其它终端。然后，你可以通过键入以下命令启动 Zsh：



```
$ zsh
```

首次启动 Zsh 时，会要求你选择一些配置选项。这些都可以在以后更改，因此请按 `1` 继续。



```
This is the Z Shell configuration function for new users, zsh-newuser-install.

(q)  Quit and do nothing.

(0)  Exit, creating the file ~/.zshrc

(1)  Continue to the main menu.
```

偏好设置分为四类，因此请从顶部开始。


1. 第一个类使你可以选择在 shell 历史记录文件中保留多少个命令。默认情况下，它设置为 1,000 行。
2. Zsh 补全是其最令人兴奋的功能之一。为了简单起见，请考虑使用其默认选项激活它，直到你习惯了它的工作方式。按 `1` 使用默认选项，按 `2` 手动设置选项。
3. 选择 Emacs 式键绑定或 Vi 式键绑定。Bash 使用 Emacs 式绑定，因此你可能已经习惯了。
4. 最后，你可以了解（以及设置或取消设置）Zsh 的一些精妙的功能。例如，当你提供不带命令的非可执行路径时，可以通过让 Zsh 来改变目录而无需你使用 `cd` 命令。要激活这些额外选项之一，请输入选项号并输入 `s` 进行设置。请尝试打开所有选项以获得完整的 Zsh 体验。你可以稍后通过编辑 `~/.zshrc` 取消设置它们。


要完成配置，请按 `0`。


### 使用 Zsh


刚开始，Zsh 的使用感受就像使用 Bash 一样，这无疑是其众多功能之一。例如，Bash 和 Tcsh 之间就存在严重的差异，因此如果你必须在工作中或在服务器上使用 Bash，而 Zsh 就可以在家里轻松尝试和使用，这样在 Bash 和 Zsh 之间轻松切换就是一种便利。


#### 在 Zsh 中改变目录


正是这些微小的差异使 Zsh 变得好用。首先，尝试在没有 `cd` 命令的情况下，将目录更改为 `Documents` 文件夹。简直太棒了，难以置信。如果你输入的是目录路径而没有进一步的指令，Zsh 会更改为该目录：



```
% Documents
% pwd
/home/seth/Documents
```

而这会在 Bash 或任何其他普通 shell 中导致错误。但是 Zsh 却根本不是普通的 shell，而这仅仅才是开始。


#### 在 Zsh 中搜索


当你想使用普通 shell 程序查找文件时，可以使用 `find` 或 `locate` 命令。最起码，你可以使用 `ls -R` 来递归地列出一组目录。Zsh 内置有允许它在当前目录或任何其他子目录中查找文件的功能。


例如，假设你有两个名为 `foo.txt` 的文件。一个位于你的当前目录中，另一个位于名为 `foo` 的子目录中。在 Bash Shell 中，你可以使用以下命令列出当前目录中的文件：



```
$ ls
foo.txt
```

你可以通过明确指明子目录的路径来列出另一个目录：



```
$ ls foo
foo.txt
```

要同时列出这两者，你必须使用 `-R` 开关，并结合使用 `grep`：



```
$ ls -R | grep foo.txt
foo.txt
foo.txt
```

但是在 Zsh 中，你可以使用 `**` 速记符号：



```
% ls **/foo.txt
foo.txt
foo.txt
```

你可以在任何命令中使用此语法，而不仅限于 `ls`。想象一下在这样的场景中提高的效率：将特定文件类型从一组目录中移动到单个位置、将文本片段串联到一个文件中，或对日志进行抽取。


### 使用 Zsh 的制表符补全


制表符补全是 Bash 和其他一些 Shell 中的高级用户功能，它变得司空见惯，席卷了 Unix 世界。Unix 用户不再需要在输入冗长而乏味的路径时使用通配符（例如输入 `/h*/s*h/V*/SCS/sc*/comp*/t*/a*/*9/04/LS*boat*v`，比输入 `/home/seth/Videos/SCS/scenes/composite/takes/approved/109/04/LS_boat-port-cargo-mover.mkv` 要容易得多）。相反，他们只要输入足够的唯一字符串即可按 `Tab` 键。例如，如果你知道在系统的根目录下只有一个以 `h` 开头的目录，则可以键入 `/h`，然后单击 `Tab`。快速、简单、高效。它还会确认路径存在；如果 `Tab` 无法完成任何操作，则说明你在错误的位置或输入了错误的路径部分。


但是，如果你有许多目录有五个或更多相同的首字母，`Tab` 会坚决拒绝进行补全。尽管在大多数现代终端中，它将（至少会）显示阻止其进行猜测你的意思的文件，但通常需要按两次 `Tab` 键才能显示它们。因此，制表符补全通常会变成来回按下键盘上字母和制表符，以至于你好像在接受钢琴独奏会的训练。


Zsh 通过循环可能的补全来解决这个小问题。如果键入 `ls ~/D` 并按 `Tab`，则 Zsh 首先使用 `Documents` 来完成命令；如果再次按 `Tab`，它将提供 `Downloads`，依此类推，直到找到所需的选项。


### Zsh 中的通配符


在 Zsh 中，通配符的行为不同于 Bash 中用户所习惯的行为。首先，可以对其进行修改。例如，如果要列出当前目录中的所有文件夹，则可以使用修改后的通配符：



```
% ls
dir0   dir1   dir2   file0   file1
% ls *(/)
dir0   dir1   dir2
```

在此示例中，`(/)` 限定了通配符的结果，因此 Zsh 仅显示目录。要仅列出文件，请使用 `(.)`。要列出符号链接，请使用 `(@)`。要列出可执行文件，请使用 `(*)`。



```
% ls ~/bin/*(*)
fop  exify  tt
```

Zsh 不仅仅知道文件类型。它也可以使用相同的通配符修饰符约定根据修改时间列出。例如，如果要查找在过去八个小时内修改的文件，请使用 `mh` 修饰符（即 “modified hours” 的缩写）和小时的负整数：



```
% ls ~/Documents/*(mh-8)
cal.org   game.org   home.org
```

要查找超过（例如）两天前修改过的文件，修饰符更改为 `md`（即 “modified day” 的缩写），并带上天数的正整数：



```
% ls ~/Documents/*(+2)
holiday.org
```

通配符修饰符和限定符还可以做很多事情，因此，请阅读 [Zsh 手册页](https://linux.die.net/man/1/zsh)，以获取全部详细信息。


#### 通配符的副作用


要像在 Bash 中使用通配符一样使用它，有时必须在 Zsh 中对通配符进行转义。例如，如果要在 Bash 中将某些文件复制到服务器上，则可以使用如下通配符：



```
$ scp IMG_*.JPG seth@example.com:~/www/ph*/*19/09/14
```

这在 Bash 中有效，但是在 Zsh 中会返回错误，因为它在发出 `scp` 命令之前尝试在远程端扩展该变量（通配符）。为避免这种情况，必须转义远程变量（通配符）：



```
% scp IMG_*.JPG seth@example.com:~/www/ph\*/\*19/09/14
```

当你切换到新的 shell 时，这些小异常可能会使你感到沮丧。使用 Zsh 时会遇到的问题不多（体验过 Zsh 后切换回 Bash 的可能遇到更多），但是当它们发生时，请保持镇定且坦率。严格遵守 POSIX 的情况很少会出错，但是如果失败了，请查找问题以解决并继续。对于许多在工作中困在一个 shell 上而在家中困在另一个 shell 上的用户来说，[hyperpolyglot.org](http://hyperpolyglot.org/unix-shells) 已被证明其是无价的。


在我的下一篇 Zsh 文章中，我将向你展示如何安装主题和插件以定制你的 Z-Shell 甚至 Z-ier。




---


via: <https://opensource.com/article/19/9/getting-started-zsh>


作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
Z-shell (or Zsh) is an interactive Bourne-like POSIX shell known for its abundance of innovative features. Z-Shell users often cite its many conveniences and credit it for increased efficiency and extensive customization.

If you're relatively new to Linux or Unix but experienced enough to have opened a terminal and run a few commands, you have probably used the Bash shell. Bash is arguably the definitive free software shell, partly because of its progressive features and partly because it ships as the default shell on most of the popular Linux and Unix operating systems. However, the more you use a shell, the more you start to find small things that might be better for the way you want to use it. If there's one thing open source is famous for, it's *choice*. Many people choose to "graduate" from Bash to Z.

## What is Zsh?

A shell is just an interface to your operating system. An interactive shell allows you to type in commands through what is called *standard input*, or **stdin**, and get output through *standard output* and *standard error*, or **stdout** and **stderr**. There are many shells, including Bash, Csh, Ksh, Tcsh, Dash, and Zsh. Each has features based on what its programmers thought would be best for a shell. Whether those features are good or bad is up to you, the end user.


Zsh has features like interactive Tab completion, automated file searching, regex integration, advanced shorthand for defining command scope, and a rich theme engine. These features are included in an otherwise familiar Bourne-like shell environment, meaning that if you already know and love Bash, you'll find Zsh familiar—except with more features. You might think of it as a kind of Bash++.

## Installing Zsh

Install Zsh with your package manager.

On Fedora, RHEL, and CentOS:

`$ sudo dnf install zsh`


On Ubuntu and Debian:

`$ sudo apt install zsh`


On MacOS, you can install it using MacPorts:

`$ sudo port install zsh`


Or with Homebrew:

`$ brew install zsh`


It's possible to run Zsh on Windows, but only on top of a Linux or Linux-like layer such as [Windows Subsystem for Linux](https://devblogs.microsoft.com/commandline/category/bash-on-ubuntu-on-windows/) (WSL) or [Cygwin](https://www.cygwin.com/). That installation is out of scope for this article, so refer to Microsoft documentation.

## Setting up Zsh

Zsh is not a terminal emulator; it's a shell that runs inside a terminal emulator. So, to launch Zsh, you must first launch a terminal window such as GNOME Terminal, Konsole, Terminal, iTerm2, rxvt, or another terminal of your preference. Then you can launch Zsh by typing:

`$ zsh`


The first time you launch Zsh, you're asked to choose some configuration options. These can all be changed later, so press **1** to continue.

```
This is the Z Shell configuration function for new users, zsh-newuser-install.
(q) Quit and do nothing.
(0) Exit, creating the file ~/.zshrc
(1) Continue to the main menu.
```


There are four categories of preferences, so just start at the top.

- The first category lets you choose how many commands are retained in your shell history file. By default, it's set to 1,000 lines.
- Zsh completion is one of its most exciting features. To keep things simple, consider activating it with its default options until you get used to how it works. Press
**1**for default options,**2**to set options manually. - Choose Emacs or Vi key bindings. Bash uses Emacs bindings, so you may be used to that already.
- Finally, you can learn about (and set or unset) some of Zsh's subtle features. For instance, you can stop using the
**cd**command by allowing Zsh to initiate a directory change when you provide a non-executable path with no command. To activate one of these extra options, type the option number and enter**s**to*set*it. Try turning on all options to get the full Zsh experience. You can unset them later by editing**~/.zshrc**.

To complete configuration, press **0**.

## Using Zsh

At first, Zsh feels a lot like using Bash, which is unmistakably one of its many features. There are serious differences between, for instance, Bash and Tcsh, so being able to switch between Bash and Zsh is a convenience that makes Zsh easy to try and easy to use at home if you have to use Bash at work or on your server.

### Change directory with Zsh

It's the small differences that make Zsh nice. First, try changing the directory to your Documents folder *without the cd command*. It seems too good to be true; but if you enter a directory path with no further instruction, Zsh changes to that directory:

```
% Documents
% pwd
/home/seth/Documents
```


That renders an error in Bash or any other normal shell. But Zsh is far from normal, and this is just the beginning.

### Search with Zsh

When you want to find a file using a normal shell, you probably resort to the **find** or **locate** command. At the very least, you may have used **ls -R** for a recursive listing of a set of directories. Zsh has a built-in feature allowing it to find a file in the current or any other subdirectory.

For instance, assume you have two files called **foo.txt**. One is located in your current directory, and the other is in a subdirectory called **foo**. In a Bash shell, you can list the file in the current directory with:

```
$ ls
foo.txt
```


and you can list the other one by stating the subdirectory's path explicitly:

```
$ ls foo
foo.txt
```


To list both, you must use the **-R** switch, maybe combined with **grep**:

```
$ ls -R | grep foo.txt
foo.txt
foo.txt
```


But in Zsh, you can use the ****** shorthand:

```
% ls **/foo.txt
foo.txt
foo.txt
```


And you can use this syntax with any command, not just with **ls**. Imagine your increased efficiency when moving specific file types from one collection of directories to a single location, or concatenating snippets of text into a file, or grepping through logs.

## Using Zsh Tab completion

Tab completion is a power-user feature in Bash and some other shells, and it took the Unix world by storm when it became commonplace. No longer did Unix users have to resort to wildcards when typing long and tedious paths (such as **/h*/s*h/V*/SCS/sc*/comp*/t*/a*/*9/04/LS*boat*v**, which is a lot easier than typing **/home/seth/Videos/SCS/scenes/composite/takes/approved/109/04/LS_boat-port-cargo-mover.mkv**). Instead, they could just press the Tab key when they entered enough of a unique string. For example, if you know there's only one directory starting with an **h** at the root level of your system, you might type **/h** and then hit Tab. It's fast, it's simple, it's efficient. It also confirms a path exists; if Tab doesn't complete anything, you know you're looking in the wrong place or you mistyped part of the path.

However, if you have many directories that share five or more of the same first letters, Tab staunchly refuses to complete. While in most modern terminals it will (at least) reveal the files blocking it from guessing what you mean, it usually takes two Tab presses to reveal them; therefore, Tab completion often becomes such an interplay of letters and Tabs across your keyboard that you feel like you're training for a piano recital.

Zsh solves this minor annoyance by cycling through possible completions. If you type **ls ~/D** and press Tab, Zsh completes your command with **Documents** first; if you press Tab again, it offers **Downloads**, and so on until you find the one you want.

## Wildcards in Zsh

Wildcards behave differently in Zsh than what Bash users are used to. First of all, they can be modified. For example, if you want to list all folders in your current directory, you can use a modified wildcard:

```
% ls
dir0 dir1 dir2 file0 file1
% ls *(/)
dir0 dir1 dir2
```


In this example, the **(/)** qualifies the results of the wildcard so Zsh will display only directories. To list just the files, use **(.)**. To list symlinks, use **(@)**. To list executable files, use **(*)**.

```
% ls ~/bin/*(*)
fop exify tt
```


Zsh isn't aware of file types only. It can also list according to modification time, using the same wildcard modifier convention. For example, if you want to find a file that was modified within the past eight hours, use the **mh** modifier (for **modified** and **hours**) and the negative integer of hours:

```
% ls ~/Documents/*(mh-8)
cal.org game.org home.org
```


To find a file modified more than (for instance) two days ago, the modifiers change to **md** (for **modified** and **day**) with a positive integer:

```
% ls ~/Documents/*(+2)
holiday.org
```


There's a lot more you can do with wildcard modifiers and qualifiers, so read the [Zsh man page](https://linux.die.net/man/1/zsh) for full details.

### The wildcard side effect

To use wildcards the way you would use them in Bash, sometimes they must be escaped in Zsh. For instance, if you're copying some files to your server in Bash, you might use a wildcard like this:

`$ scp IMG_*.JPG seth@example.com:~/www/ph*/*19/09/14`


That works in Bash, but Zsh returns an error because it tries to expand the variables on the remote side before issuing the **scp** command. To avoid this, you must escape the remote variables:

`% scp IMG_*.JPG seth@example.com:~/www/ph\*/\*19/09/14`


It's these types of little exceptions that can frustrate you when you're switching to a new shell. There aren't many when using Zsh (there are probably more when switching back to Bash after experiencing Zsh) but when they happen, remain calm and be explicit. Rarely will you go wrong to adhere strictly to POSIX—but if that fails, look up the problem to solve it and move on. [Hyperpolyglot.org](http://hyperpolyglot.org/unix-shells) has proven invaluable to many users stuck on one shell at work and another at home.

In my next Zsh article, I'll show you how to install themes and plugins to make your Z-Shell even Z-ier.

## 2 Comments