Zsh (简体中文)

From ArchWiki
翻译状态:本文是 Zsh翻译。上次翻译日期:2020-08-25。如果英文版本有所更改,则您可以帮助同步翻译。

Zsh 是一款功能强大的 Shell 软件,既可以作为交互式终端来使用,也可以作为脚本语言解释器来使用。它在兼容 POSIX 的 sh 的同时(默认不兼容,仅在使用 emulate sh 时兼容),还改进了 Tab 补全通配符等功能。

Zsh FAQ 说明了使用 Zsh 的原因。

安装

在开始安装之前,用户可能想要查看一下当前正在使用的 Shell 软件:

$ echo $SHELL

安装 zsh 包。如果想要更精确地补全命令,可以同时安装 zsh-completions 包。

初始配置

在终端里面输入以下命令,确保已经正确安装了 Zsh:

$ zsh

运行后你应该会看到新用户向导(zsh-newuser-install),它可以协助你完成一些基础配置。如果要跳过这一步骤,可以按 q 退出。如果你没有看到新用户向导(zsh-newuser-install),可以手动运行以下命令:

$ autoload -Uz zsh-newuser-install
$ zsh-newuser-install -f
注意: 确保你的终端尺寸至少为 72×15 大小,否则新用户向导(zsh-newuser-install)将无法运行。

将 Zsh 设为默认 Shell 软件

将 Shell 改为 /usr/bin/zsh。参见 更改你的 Shell 软件

提示: 如果要替换 bash,用户可能希望能够将 ~/.bashrc 文件的某些代码转移到 ~/.zshrc 文件(例如:命令行提示符和别名),以及将 ~/.bash_profile 文件的代码转移到 ~/.zprofile 文件(例如:启动 X Window System 的代码)。

配置文件介绍

当 Zsh 启动时,它会按照顺序依次读取下面的配置文件:

/etc/zsh/zshenv
该文件应该包含用来设置PATH 环境变量以及其他一些环境变量的命令;不应该包含那些可以产生输出结果或者假设终端已经附着到 tty 上的命令。
~/.zshenv
该文件和 /etc/zsh/zshenv 相似,但是它是针对每个用户而言的。一般来说是用来设置一些有用的环境变量。
/etc/zsh/zprofile
这是一个全局的配置文件,在用户登录的时候加载。一般是用来在登录的时候执行一些命令。请注意,在 Arch Linux 里该文件默认包含一行配置,用来加载 /etc/profile 文件,详见 #全局配置文件
/etc/profile
在登录时,该文件应该被所有和伯克利(Bourne)终端相兼容的终端加载:它在登录的的时候会加载应用相关的配置(/etc/profile.d/*.sh)。注意在 Arch Linux 里,Zsh 会默认加载该文件。
~/.zprofile
该文件一般用来在登录的时候自动执行一些用户脚本。
/etc/zsh/zshrc
当 Zsh 被作为交互式终端的时候,会加载这样一个全局配置文件。
~/.zshrc
当 Zsh 被作为交互式终端的时候,会加载这样一个用户配置文件。
/etc/zsh/zlogin
在登录完毕后加载的一个全局配置文件。
~/.zlogin
/etc/zsh/zlogin 相似,但是它是针对每个用户而言的。
/etc/zsh/zlogout
在注销的时候被加载的一个全局配置文件。
~/.zlogout
/etc/zsh/zlogout 相似,但是它是针对每个用户而言的.
注意:
  • 在 Arch 源中的 zsh 所使用的文件路径和 Zsh 的 man 手册中默认的不同(详见 #全局配置文件
  • /etc/profile 不是 Zsh 常规启动配置文件的一部分,但是 Arch 源中的 zsh 会在 /etc/zsh/zprofile 里面加载它。用户应该注意 /etc/profile 里面设置的 $PATH 环境变量会覆盖掉 ~/.zshenv 里面配置的任何 $PATH。为了防止这一点,请在 ~/.zshrc 当中设置 $PATH(不推荐替换掉 /etc/zsh/zprofile 里面的默认配置,因为这样会破坏其他提供了 /etc/profile.d 的软件包和 Zsh 的联动关系)

全局配置文件

有时候你可能想提供一些所有 Zsh 用户共享的配置。在帮助手册 zsh(1) 提到的一些全局配置文件(例如 /etc/zshrc)的路径,在 Arch Linux 里是有一些不同的,因为其路径已经被编译为 [1] /etc/zsh/

所以,Arch 源中 zsh 的全局配置文件会使用 /etc/zsh/zshrc 而不是 /etc/zshrc。类似的还有 /etc/zsh/zshenv/etc/zsh/zlogin/etc/zsh/zlogout。注意这些文件不是默认就被创建好的,你可以根据需要来创建它们。

唯一的例外是 zprofile,请使用 /etc/profile

配置 Zsh

尽管 Zsh 基本不需要怎么配置就能满足大多数用户的需求,但是因为其中包含太多的可定制选项,导致配置 Zsh 可能会比较耗时。

简单的 .zshrc

下面是一个简单的 .zshrc 配置文件,它提供一个配置 Zsh 的生动的例子。你可以将下面的配置保存为文件 .zshrc 来使用它。

~/.zshrc
autoload -U compinit promptinit
compinit
promptinit

# 设置 walters 主题的默认命令行提示符
prompt walters
提示: 你可以执行命令 source ~/.zshrc 来生效修改的配置,而不需要重新登录

配置 $PATH

将下面的配置放到 ~/.zshenv 中:

~/.zshenv
typeset -U path
path=(~/bin /other/things/in/path $path[@])

另请参见 《A User's Guide to the Z-Shell(Z-Shell 用户指南)》#配置 Zsh 中的相关内容。

命令补全

也许 Zsh 最引人注目的特性就是它先进的自动补全功能。在 ~/.zshrc 最后加入下面的配置,开启自动补全:

~/.zshrc
autoload -U compinit
compinit

上面的补全配置包括 ssh/scp/sftp 命令中的主机名(host name)补全。但是要让这个特性正常工作,你需要防止 ~/.ssh/known_hosts 中的主机名被散列化(hash)。

警告: 主机名去散列化可能会导致本机成为 跳跃式攻击("Island-hopping" attacks)的跳板。如果你希望 Zsh 自动补全主机名,你可以注释掉 /etc/ssh/ssh_config 当中的这行配置,或者设置为 no
/etc/ssh/ssh_config
#HashKnownHosts yes

你可以将原来的 ~/.ssh/known_hosts 移动到别的地方,之后 ssh 创建的 ~/.ssh/known_hosts 文件就不会散列化主机名(但是之前信任的主机如果需要,还得重新导入进来)。具体请参考 ssh 的 README 文件中散列化主机名的相关内容。

添加下面的配置可以启动使用方向键控制的自动补全:

~/.zshrc
zstyle ':completion:*' menu select
按两次 tab 键启动菜单

添加下面的配置可以启动命令行别名的自动补全:

~/.zshrc
setopt completealiases

"command not found" 钩子

另请参见 Pkgfile#Command not found

消除历史记录中的重复条目

~/.zshrc
setopt HIST_IGNORE_DUPS

假如目前的历史记录中已经有重复条目,可以运行下面的命令清除

$ sort -t ";" -k 2 -u ~/.zsh_history | sort -o ~/.zsh_history

ttyctl 命令

[2] 描述了 Zsh 中的 ttyctl 命令。它可以用来锁定/解锁(freeze/unfreeze)终端。许多程序会修改终端的状态并且在异常退出的时候不会还原初始状态。下面的配置可以避免手动重置终端。

~/.zshrc
ttyctl -f

快捷键绑定

Zsh 使用自带的 zle 代替 readline,并且不会读取 /etc/inputrc 或者 ~/.inputrc。 Zle 有 emacsvi 两个模式,默认情况下它根据环境变量 $EDITOR 来决定使用哪一个模式,如果为空默认为 emacs 模式。使用 bindkey -e 或者 bindkey -v 来手动指定模式。 另请参见 zshwiki: bindkeys.

ncurses 应用的快捷键绑定

(译者注:ncurses 是一个字符界面下的 GUI 框架)如果直接将 ncurses 应用绑定到某个快捷键,那么它会失去交互性。可以使用变量 BUFFER 来解决这个问题。下面的例子是使用 Alt+\ 来打开 ncmpcpp:

~/.zshrc
ncmpcppShow() { BUFFER="ncmpcpp"; zle accept-line; }
zle -N ncmpcppShow
bindkey '^[\' ncmpcppShow

另一种方法

该方法会在启动应用之前,将你的输入保存在一行当中。

~/.zshrc
ncmpcppShow() { ncmpcpp <$TTY; zle redisplay; }
zle -N ncmpcppShow
bindkey '^[\' ncmpcppShow

文件管理器的快捷键绑定

图形化文件管理器中使用快捷键可能很实用(译者注:你也可以在 Zsh 中自定义快捷键达到这样的效果)。第一个使用 Alt+Left 让用户撤销最近的 cd 操作,第二个使用 Alt+Up 让用户进入上层目录。这两个快捷键同时也会显示目录中的内容。

~/.zshrc
cdUndoKey() {
  popd      > /dev/null
  zle       reset-prompt
  echo
  ls
  echo
}

cdParentKey() {
  pushd .. > /dev/null
  zle      reset-prompt
  echo
  ls
  echo
}

zle -N                 cdParentKey
zle -N                 cdUndoKey
bindkey '^[[1;3A'      cdParentKey
bindkey '^[[1;3D'      cdUndoKey

查找历史记录

~/.zshrc
[[ -n "${key[PageUp]}"   ]]  && bindkey  "${key[PageUp]}"    history-beginning-search-backward
[[ -n "${key[PageDown]}" ]]  && bindkey  "${key[PageDown]}"  history-beginning-search-forward

使用这段配置会只显示以当前命令开头的历史记录。

命令提示符

这是一种 Zsh 中简单快速设置彩色提示符的方法。首先确保 .zshrc 中配置了自动加载提示符。具体配置如下:

~/.zshrc
autoload -U promptinit
promptinit

然后你可以运行下面的命令查看可用的提示符:

$ prompt -l

使用下面命令来启动其中一种提示符,例如启动 "walters" 提示符:

$ prompt walters

使用下面的命令查看所有可用的主题:

$ prompt -p

自定义命令提示符

对于那些不满足默认提示符的用户,Zsh 提供了自定义提示符的方法。除了普通终端会提供的靠左的提示符外,Zsh 还提供了靠右的提示符。通过配置 PROMPT= 来设置。

可以参考 Prompt Expansion 来获得所有可用的 prompt variables 和 conditional substrings。

彩色

Zsh 设置彩色提示符的方法和 Bash 不同。 在 .zshrcPROMPT= 前面添加 autoload -U colors && colors 来启用彩色提示符。通常你需要将这些配置放在 %{ [...] %} 里面确保光标不移动。

$fg[color] 会设置文本的颜色(红,绿,蓝,等等。默认是和之前的文本颜色保持一致)

命令 描述
%F{color} [...] %f 和前面介绍的 $fg 是一样的,但是更简洁。还可以在 F 前面添加数字。
$fg_no_bold[color] 设置文本为非粗体同时设定文本颜色
$fg_bold[color] 设置文本为粗体同时设定文本颜色
$reset_color 重置文本颜色(改为默认颜色)。不会重置粗体设定。使用 %b 来重置粗体设定。可以使用 %f 来简化配置。
%K{color} [...] %k 设置背景颜色。和非粗体文本颜色一样。任何单一数字前缀会设置背景为黑色。
Possible color values
black or 0 red or 1
绿 green or 2 yellow or 3
blue or 4 magenta or 5
cyan or 6 white or 7
注意: 粗体文本不一定会和普通文本使用同一种颜色。例如, $fg['yellow'] 会使用暗一点的黄色, 而 $fg_bold['yellow'] 可能会使用亮一点的黄色。(译者注:具体是由你的终端模拟器配置决定的)

示例

左右双边的提示符:

PROMPT="%{$fg[red]%}%n%{$reset_color%}@%{$fg[blue]%}%m %{$fg[yellow]%}%1~ %{$reset_color%}%#"
RPROMPT="[%{$fg[yellow]%}%?%{$reset_color%}]"

效果如下(忽略颜色):

username@host ~ %                                                         [0]

目录栈(dirstack)

Zsh 可以配置 DIRSTACK 相关变量来加速 cd 访问常用目录。在你的配置文件中添加下面的配置:

.zshrc
DIRSTACKFILE="$HOME/.cache/zsh/dirs"
if [[ -f $DIRSTACKFILE ]] && [[ $#dirstack -eq 0 ]]; then
  dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
  [[ -d $dirstack[1] ]] && cd $dirstack[1]
fi
chpwd() {
  print -l $PWD ${(u)dirstack} >$DIRSTACKFILE
}

DIRSTACKSIZE=20

setopt autopushd pushdsilent pushdtohome

## Remove duplicate entries
setopt pushdignoredups

## This reverts the +/- operators.
setopt pushdminus

现在你可以使用

dirs -v

来打印目录栈(dirstack)。使用 cd -<NUM> 来跳转到以前访问过的目录。你还可以在连字符后面使用自动补全,非常方便。

帮助命令

bash 不同的是 zsh 没有内置的 help 命令,要想在 zsh 中使用 help,可以添加下面的配置:

autoload -U run-help
autoload run-help-git
autoload run-help-svn
autoload run-help-svk
unalias run-help
alias help=run-help

仿 Fish 命令高亮

(译者注:Fish 是一款比较新的终端软件)Fish 提供了非常强大的命令高亮。如果你希望在 zsh 中使用类似的功能,你可以从官方仓库里安装 zsh-syntax-highlighting,然后添加下面的配置到你的 zshrc 中:

source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

.zshrc 样例

配置框架

  • oh-my-zsh 是一个著名的,社区驱动的框架,它拥有很多有用的函数,helpers,插件,主题,可以用来简化复杂的 Zsh 配置。
  • Prezto - Instantly Awesome Zsh(可以通过 prezto-gitAUR 获取) 它是一个模块化的 Zsh 配置框架,里面有很多顺手的默认配置、别名、函数、自动补全和命令提示符主题。
  • Antigen (可以通过 antigen-gitAUR 获取) 这个一个 zsh 插件管理器,受到 oh-my-zsh 和 vundle 的启发

自启动程序

注意: $ZDOTDIR 默认指向 $HOME

Zsh 经常执行 /etc/zsh/zshenv$ZDOTDIR/.zshenv,所以不要让他们变得很臃肿。

如果是一个登录了的终端,会加载 /etc/profile 然后加载 $ZDOTDIR/.zprofile。然后如果是交互式模式,会继续加载 /etc/zsh/zshrc 接着加载 $ZDOTDIR/.zshrc 。最后如果还是登录了的终端,/etc/zsh/zlogin$ZDOTDIR/.zlogin 也会被加载。

另请参见 zsh(1)STARTUP/SHUTDOWN FILES 章节。

刷新自动补全

一般来说,compinit 不会自动在 $PATH 里面查找新的可执行文件。例如当你安装了一个新的软件包,/usr/bin 里的新文件不会立即自动添加到自动补全当中。所以你需要执行下面的命令来将它们添加进自动补全:

$ rehash

这个 'rehash' 可以被放到你的 zshrc 来自动执行

~/.zshrc
zstyle ':completion:*' rehash true
注意: 这个技巧在 Oh My Zsh [3] 的一次 PR 中被发现

卸载

在卸载 zsh 之前请先更换默认终端。

警告: 如果不遵循下面的步骤可能会导致用户无法访问任何终端

运行下面的命令:

$ chsh -s /bin/bash user

每一个使用 zsh 作为默认终端的用户都需要执行一遍条命令。当完成之后就可以把 zsh 软件包删除了。

当然你也也可以以 root 身份修改 /etc/passwd 文件,来批量更改用户的默认终端。

警告: 强烈建议使用 vipw 来修改 /etc/passwd,因为它可以帮助你消灭格式错误

例如将下面的配置中的 /bin/zsh

username:x:1000:1000:Full Name,,,:/home/username:/bin/zsh

改成 /bin/bash

username:x:1000:1000:Full Name,,,:/home/username:/bin/bash

另请参见