跳转至内容

Zsh

来自 ArchWiki

Zsh 是一个强大的 Shell,既可以作为交互式 Shell,也可以作为脚本语言解释器。虽然兼容 POSIX sh (默认不兼容,只有在执行 emulate sh 时才会兼容),但它提供了诸如改进的 标签补全globbing 等优点。

Zsh FAQ 提供了更多使用 Zsh 的理由。

安装

开始之前,用户可能想知道当前正在使用的 Shell 是什么

$ echo $SHELL

安装 zsh 包。为了获得额外的补全定义,也请安装 zsh-completions 包。

初始配置

通过在终端中运行以下命令,确保 Zsh 已正确安装:

$ zsh

您现在应该会看到 zsh-newuser-install,它将引导您完成一些基本配置。如果您想跳过它,请按 q。如果您没有看到它,可以手动调用:

$ autoload -Uz zsh-newuser-install
$ zsh-newuser-install -f
注意 确保您的终端大小至少为 72x15,否则 zsh-newuser-install 将无法运行。

将 Zsh 设置为默认 Shell

将您的 Shell 更改为 /usr/bin/zsh。请参阅 Command-line shell#Changing your default shell

提示 如果您替换 bash,用户可能想将一些代码从 ~/.bashrc 移动到 ~/.zshrc (例如提示符和 别名),并将一些代码从 ~/.bash_profile 移动到 ~/.zprofile (例如 启动 X Window System 的代码)。

启动/关闭文件

提示 请参阅 A User's Guide to the Z-Shell,了解交互式 Shell 和登录 Shell 的解释,以及在启动文件中放置什么。
  • 如果未设置 $ZDOTDIR,则使用 $HOME 作为替代。
  • 如果在任何文件中取消设置了 RCS 选项,则在该文件之后将不再读取任何配置文件。
  • 如果在任何文件中取消设置了 GLOBAL_RCS 选项,则在该文件之后将不再读取任何全局配置文件 (/etc/zsh/*)。

启动时,Zsh 默认将按以下顺序从以下文件中读取命令,前提是它们存在。

  • /etc/zsh/zshenv 用于为所有用户设置 环境变量;它不应包含产生输出或假定 Shell 已连接到 TTY 的命令。当此文件存在时,它将 *始终* 被读取,此行为无法覆盖。
  • $ZDOTDIR/.zshenv 用于设置用户的环境变量;它不应包含产生输出或假定 Shell 已连接到 TTY 的命令。当此文件存在时,它将 *始终* 被读取。
  • /etc/zsh/zprofile 用于在启动时为所有用户执行命令,将在启动为 *登录 Shell* 时读取。请注意,在 Arch Linux 上,默认情况下它包含 一行,该行会 sourced /etc/profile。在想要删除它之前,请注意以下警告!
    • /etc/profile 此文件应由所有 POSIX sh 兼容 Shell 在登录时 sourced;它会在登录时设置 $PATH 和其他环境变量以及应用程序特定的 (/etc/profile.d/*.sh) 设置。
  • $ZDOTDIR/.zprofile 用于在启动时执行用户的命令,将在启动为 *登录 Shell* 时读取。通常用于自动启动图形会话和设置会话范围的环境变量。
  • /etc/zsh/zshrc 用于为所有用户设置交互式 Shell 配置和执行命令,将在启动为 *交互式 Shell* 时读取。
  • $ZDOTDIR/.zshrc 用于设置用户的交互式 Shell 配置和执行命令,将在启动为 *交互式 Shell* 时读取。
  • /etc/zsh/zlogin 用于在初始进程结束时为所有用户执行命令,将在启动为 *登录 Shell* 时读取。
  • $ZDOTDIR/.zlogin 用于在初始进程结束时执行用户的命令,将在启动为 *登录 Shell* 时读取。通常用于自动启动命令行实用程序。不应用于自动启动图形会话,因为此时会话可能包含仅为交互式 Shell 设计的配置。
  • $ZDOTDIR/.zlogout 用于在 *登录 Shell* **退出** 时执行命令。
  • /etc/zsh/zlogout 用于在 *登录 Shell* **退出** 时为所有用户执行命令。

请参阅 图形化表示

注意 $HOME/.profile 不是 Zsh 启动文件的一部分,除非 Zsh 被调用为 shksh 并作为登录 Shell 启动,否则 **不会被 sourced**。有关 sh 和 ksh 兼容模式的更多详细信息,请参阅 zsh(1) § COMPATIBILITY
警告 请勿删除 /etc/zsh/zprofile 中的默认 一行,否则将破坏提供 /etc/profile.d/ 中某些脚本的其他软件包的完整性。

配置 Zsh

尽管 Zsh 开箱即用,但它几乎肯定没有设置为大多数用户期望的方式。但由于 Zsh 可用的定制量巨大,配置 Zsh 可能是一项艰巨且耗时的任务。有关自动配置,请参阅 #第三方扩展

简单的 .zshrc

下面包含一个示例配置文件。它提供了相当不错的默认选项集,并举例说明了 Zsh 可以定制的许多方式。为了使用此配置,请将其保存为名为 .zshrc 的文件。

提示 通过运行 source ~/.zshrc,可以在无需注销再登录的情况下应用更改。

这是一个简单的 .zshrc

~/.zshrc
autoload -Uz compinit promptinit
compinit
promptinit

# This will set the default prompt to the walters theme
prompt walters

有关提示符主题系统的更多详细信息,请参阅 #提示符主题

配置 $PATH

Zsh 将 PATH 变量与 path 数组关联。这允许您通过简单地修改 path 数组来操作 PATH。有关详细信息,请参阅 A User's Guide to the Z-Shell

~/.local/bin/ 添加到 PATH

~/.zshenv
typeset -U path PATH
path=(~/.local/bin $path)
export PATH

命令补全

Zsh 最吸引人的特性或许是其高级的自动补全功能。至少,请在 .zshrc 中启用自动补全。要启用自动补全,请将以下内容添加到您的 ~/.zshrc

~/.zshrc
autoload -Uz compinit
compinit

上述配置包括 ssh/scp/sftp 主机名补全,但要使此功能正常工作,用户不得启用 ssh 的主机名哈希 (即 ssh 客户端配置中的 HashKnownHosts 选项)。

要使用箭头键驱动的界面进行自动补全,请将以下内容添加到:

~/.zshrc
zstyle ':completion:*' menu select

按两次 Tab 键以激活菜单。

要为特权命令启用特权环境的自动补全 (例如,如果您补全的命令以 sudo 开头,补全脚本也将尝试使用 sudo 来确定您的补全),请包含:

~/.zshrc
zstyle ':completion::complete:*' gain-privileges 1
警告 这将允许 Zsh 补全脚本使用 sudo 权限运行命令。如果您使用不受信任的自动补全脚本,则不应启用此选项。
注意 这种特殊的上下文感知补全仅适用于少量命令。

自定义补全

您可以自己编写自定义补全。如果这样做,可以参考 zshcompsys(1) 手册页。

请注意,官方文档可能难以阅读。您可以尝试更简单的 zsh-completion-howto 教程,以便轻松入门。

按键绑定

Zsh 不使用 readline,而是使用自己更强大的 Zsh Line Editor (ZLE)。它不读取 /etc/inputrc~/.inputrc。请阅读 A closer look at the zsh line editor and creating custom widgets 以了解 ZLE 配置的介绍。

ZLE 有一个 Emacs 模式和一个 vi 模式。如果 VISUALEDITOR 环境变量 中的任何一个包含字符串 vi,则使用 vi 模式;否则,它将默认使用 Emacs 模式。分别使用 bindkey -ebindkey -v 来显式设置 Emacs 模式或 vi 模式。在 vi 模式下按下 Esc 键的延迟默认为 0.4 秒,您可以使用 export KEYTIMEOUT=5 将其缩短 (0.05 秒)。

按键绑定是通过将匹配按键的转义序列映射到 ZLE 小部件来分配的。可用的小部件及其操作描述和默认按键绑定列在 zshzle(1) § STANDARD WIDGETSzshcontrib(1) § ZLE FUNCTIONS 中。

在 Zsh 中设置按键绑定的推荐方法是使用 terminfo(5) 中的字符串功能。例如:[1][2]

~/.zshrc
# create a zkbd compatible hash;
# to add other keys to this hash, see: man 5 terminfo
typeset -g -A key

key[Home]="${terminfo[khome]}"
key[End]="${terminfo[kend]}"
key[Insert]="${terminfo[kich1]}"
key[Backspace]="${terminfo[kbs]}"
key[Delete]="${terminfo[kdch1]}"
key[Up]="${terminfo[kcuu1]}"
key[Down]="${terminfo[kcud1]}"
key[Left]="${terminfo[kcub1]}"
key[Right]="${terminfo[kcuf1]}"
key[PageUp]="${terminfo[kpp]}"
key[PageDown]="${terminfo[knp]}"
key[Shift-Tab]="${terminfo[kcbt]}"

# setup key accordingly
[[ -n "${key[Home]}"      ]] && bindkey -- "${key[Home]}"       beginning-of-line
[[ -n "${key[End]}"       ]] && bindkey -- "${key[End]}"        end-of-line
[[ -n "${key[Insert]}"    ]] && bindkey -- "${key[Insert]}"     overwrite-mode
[[ -n "${key[Backspace]}" ]] && bindkey -- "${key[Backspace]}"  backward-delete-char
[[ -n "${key[Delete]}"    ]] && bindkey -- "${key[Delete]}"     delete-char
[[ -n "${key[Up]}"        ]] && bindkey -- "${key[Up]}"         up-line-or-history
[[ -n "${key[Down]}"      ]] && bindkey -- "${key[Down]}"       down-line-or-history
[[ -n "${key[Left]}"      ]] && bindkey -- "${key[Left]}"       backward-char
[[ -n "${key[Right]}"     ]] && bindkey -- "${key[Right]}"      forward-char
[[ -n "${key[PageUp]}"    ]] && bindkey -- "${key[PageUp]}"     beginning-of-buffer-or-history
[[ -n "${key[PageDown]}"  ]] && bindkey -- "${key[PageDown]}"   end-of-buffer-or-history
[[ -n "${key[Shift-Tab]}" ]] && bindkey -- "${key[Shift-Tab]}"  reverse-menu-complete

# Finally, make sure the terminal is in application mode, when zle is
# active. Only then are the values from $terminfo valid.
if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then
	autoload -Uz add-zle-hook-widget
	function zle_application_mode_start { echoti smkx }
	function zle_application_mode_stop { echoti rmkx }
	add-zle-hook-widget -Uz zle-line-init zle_application_mode_start
	add-zle-hook-widget -Uz zle-line-finish zle_application_mode_stop
fi

您需要设置 key 数组并确保 ZLE 进入应用程序模式才能使用以下说明;请参阅 #按键绑定

要启用历史记录搜索,请将以下行添加到 .zshrc 文件:

~/.zshrc
autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search

[[ -n "${key[Up]}"   ]] && bindkey -- "${key[Up]}"   up-line-or-beginning-search
[[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}" down-line-or-beginning-search

通过这样做,当按下 向上向下 键时,只会显示与当前光标位置之前到当前行匹配的历史命令。

Shift, Alt, Ctrl 和 Meta 修饰键

兼容 xterm 的终端可以使用来自 user_caps(5) 的扩展按键定义。这些是 ShiftAltCtrlMetaUpDownLeftRightPageUpPageDownHomeEndDel 的组合。有关修饰键和按键组合的推荐名称列表,请参阅 zkbd 源代码

例如,对于 Ctrl+Left 移动到前一个单词的开头,以及 Ctrl+Right 移动到下一个单词的开头:

~/.zshrc
key[Control-Left]="${terminfo[kLFT5]}"
key[Control-Right]="${terminfo[kRIT5]}"

[[ -n "${key[Control-Left]}"  ]] && bindkey -- "${key[Control-Left]}"  backward-word
[[ -n "${key[Control-Right]}" ]] && bindkey -- "${key[Control-Right]}" forward-word

提示符

Zsh 提供了使用提示符主题的选项,或者对于对主题不满意 (或想扩展其用途) 的用户,则可以选择构建自定义提示符。

提示符主题

提示符主题是 Zsh 中快速轻松地设置彩色提示符的一种方式。有关提示符主题以及如何编写自己的主题的信息,请参阅 zshcontrib(1) § PROMPT THEMES

要使用主题,请确保在 .zshrc 中将提示符主题系统设置为自动加载。这可以通过将以下行添加到:

~/.zshrc
autoload -Uz promptinit
promptinit

通过运行以下命令列出可用的提示符主题:

$ prompt -l

例如,要使用 walters 主题,请输入:

$ prompt walters

要预览所有可用主题,请使用此命令:

$ prompt -p
手动安装提示符主题

可以手动安装主题,无需外部配置管理器工具。对于本地安装,首先创建一个文件夹并将其添加到 fpath 数组,例如:

$ mkdir ~/.zprompts
$ fpath=("$HOME/.zprompts" "$fpath[@]")

现在在该文件夹中创建主题文件的符号链接:

$ ln -s mytheme.zsh ~/.zprompts/prompt_mytheme_setup

如果您希望全局安装主题,请执行:

# ln -s mytheme.zsh /usr/share/zsh/functions/Prompts/prompt_mytheme_setup

现在您应该可以使用以下命令激活它:

$ prompt mytheme

如果一切正常,您可以相应地编辑您的 .zshrc

添加提示符主题,无需为每个主题创建单独文件

除了通过自己的文件添加提示符主题外,还可以从另一个文件 (如您的 .zshrc) 中添加主题,例如:

~/.zshrc
# Load promptinit
autoload -Uz promptinit && promptinit

# Define the theme
prompt_mytheme_setup() {
  PS1="%~%# "
}

# Add the theme to promptsys
prompt_themes+=( mytheme )

# Load the theme
prompt mytheme

自定义提示符

除了所有 Shell 都通用的主要左侧提示符 PS1 (PROMPT, prompt) 之外,Zsh 还支持右侧提示符 RPS1 (RPROMPT)。这两个变量是您希望设置为自定义值的变量。

其他特殊用途的提示符,如 PS2 (PROMPT2)、PS3 (PROMPT3)、PS4 (PROMPT4)、RPS1 (RPROMPT)、RPS2 (RPROMPT2) 和 SPROMPT,在 zshparam(1) § PARAMETERS USED BY THE SHELL 中进行了说明。

所有提示符都可以使用提示符转义字符进行定制。可用提示符转义字符列在 zshmisc(1) § EXPANSION OF PROMPT SEQUENCES 中。

颜色

Zsh 设置颜色的方式与 Bash 不同;您无需使用大量的 ANSI 转义序列或来自 terminfo(5) 的终端功能。Zsh 提供了方便的提示符转义字符来设置前景色、背景色和其他视觉效果;有关它们及其描述的列表,请参阅 zshmisc(1) § Visual effects

颜色 可以使用十进制整数、八种最广泛支持的颜色之一的名称,或以 # 开头后跟十六进制格式的 RGB 三元组来指定。有关 fg=colour 的更多详细信息,请参阅 zshzle(1) § CHARACTER HIGHLIGHTING

大多数终端支持以下颜色名称:

名称 编号
黑色 0
红色 1
绿色 2
黄色 3
蓝色 4
品红色 5
青色 6
白色 7

兼容 xterm 256 色的终端的颜色编号 0-255 可以在 xterm-256color 图表 中找到。

使用正确设置的 TERM 环境变量,可以使用 echoti colors 命令从 terminfo(5) 数据库中查找终端支持的最大颜色数。对于 24 位颜色,还应检查 COLORTERM 环境变量,执行 print $COLORTERM。如果它返回 24bittruecolor,则您的终端支持 16777216 (224) 种颜色,即使 terminfo 显示的数量较少。

  • 颜色 0-15 可能因终端模拟器和使用的颜色方案而异。
  • 许多终端模拟器以更亮的颜色显示粗体。
提示
  • 可以使用命令 print -P "prompt escapes" 来测试提示符转义字符,例如:
    $ print -P '%B%F{red}co%F{green}lo%F{blue}rs%f%b'
  • 如果您使用 24 位颜色,并且在不支持这些颜色的终端中,您可能想加载 zsh/nearcolor 模块。例如:
    [[ "$COLORTERM" == (24bit|truecolor) || "${terminfo[colors]}" -eq '16777216' ]] || zmodload zsh/nearcolor
    有关 zsh/nearcolor 模块的详细信息,请参阅 zshmodules(1) § THE ZSH/NEARCOLOR MODULE
示例

一个简单的无颜色提示符示例

PROMPT='%n@%m %~ %# '

显示效果

username@host ~ %

这是一个带颜色的双侧提示符示例

PROMPT='%F{green}%n%f@%F{magenta}%m%f %F{blue}%B%~%b%f %# '
RPROMPT='[%F{yellow}%?%f]'

下面是它的显示效果

username@host ~ % [0]

要使用 16-255 范围的颜色和 24 位真彩色,您可以使用分配给所需颜色的 0 到 255 的数字及其对应的十六进制颜色代码。

PROMPT='%F{2}%n%f@%F{5}%m%f %F{4}%B%~%b%f %# '
RPROMPT='[%F{3}%?%f]'
PROMPT='%F{#c0c0c0}%n%f@%F{#008000}%m%f %F{#800080}%B%~%b%f %# '
RPROMPT='[%F{#0000ff}%?%f]'

示例 .zshrc 文件

有关更多信息,请参阅 dotfiles#User repositories

技巧与提示

登录时自动启动 X

请参阅 xinit#Autostart X at login

程序异常退出后恢复终端设置

许多程序会改变终端状态,并且在异常退出时 (例如崩溃或遇到 SIGINT) 通常不会恢复终端设置。

这通常可以通过执行 reset(1) 来解决。

$ reset

以下各节描述了避免手动重置终端的方法。

ttyctl 命令

ttyctl 命令可用于“冻结/解冻”终端。要在启动时冻结交互式 Shell,请使用以下命令:

~/.zshrc
ttyctl -f

使用转义序列重置终端

备用的行绘制字符集可能会损坏终端,而 ttyctl 无法阻止这种情况。

一个简单的解决方案是在 precmd 钩子函数中输出重置终端的转义序列,这样每次在绘制提示符之前都会执行它们。例如,使用 转义序列 \e[0m\e(B\e)0\017\e[?5l\e7\e[0;0r\e8

~/.zshrc
autoload -Uz add-zsh-hook

function reset_broken_terminal () {
	printf '%b' '\e[0m\e(B\e)0\017\e[?5l\e7\e[0;0r\e8'
}

add-zsh-hook -Uz precmd reset_broken_terminal

要测试它是否有效,请运行:

$ print '\e(0\e)B'

记住最近的目录

Dirstack

Zsh 可以配置为记住 DIRSTACKSIZE 个最近访问的文件夹。然后可以使用它们非常快速地 cd 到这些文件夹。您需要向您的配置文件添加几行:

~/.zshrc
autoload -Uz add-zsh-hook

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

DIRSTACKSIZE='20'

setopt AUTO_PUSHD PUSHD_SILENT PUSHD_TO_HOME

## Remove duplicate entries
setopt PUSHD_IGNORE_DUPS

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

现在使用

$ dirs -v

来打印 dirstack。使用 cd -<NUM> 返回到访问过的文件夹。在连字符后使用自动补全。当使用自动补全菜单时,这非常有用。

  • 当有多个 zsh 会话打开并尝试 cd 时,这将无效,因为两个会话会写入同一文件,从而导致冲突。
  • 您可能需要创建 $HOME/.cache/zsh 目录,以避免出现 no such file or directory 错误。

cdr

cdr 允许您将工作目录更改为自动维护的列表中以前的工作目录。它将所有条目存储在跨会话和 (默认情况下) 跨会话中终端模拟器维护的文件中。

有关设置说明,请参阅 zshcontrib(1) § REMEMBERING RECENT DIRECTORIES

zoxide

zoxide 是一个更智能的 cd 命令,它允许您用很少的按键即可导航到任何地方。它会记住您经常使用的目录,并使用评分机制来猜测您想去哪里。

帮助命令

Bash 不同,Zsh 不启用内置的 help 命令,而是提供 run-help。默认情况下,run-helpman 的别名,可以通过在命令前添加它来手动执行,也可以通过键盘快捷键 Alt+hEsc h 来调用当前输入的命令。

由于默认它只是 man 的别名,所以它只对外部命令有效。要改进其功能,使其对 Shell 内置命令和其他 Shell 功能也有效,您需要使用 run-help 函数。有关 run-help 及其助手函数的更多信息,请参阅 zshcontrib(1)

首先加载 run-help 函数,然后删除现有的 run-help 别名。为了方便,可以为 help 设置别名,使其指向 run-help。例如,在您的 zshrc 中添加以下内容:

autoload -Uz run-help
(( ${+aliases[run-help]} )) && unalias run-help
alias help=run-help

必须单独启用助手函数

autoload -Uz run-help-git run-help-ip run-help-openssl run-help-p4 run-help-sudo run-help-svk run-help-svn

例如,run-help git commit 命令现在将打开 man page git-commit(1),而不是 git(1)

持久化 rehash

通常,compinit 不会自动查找 $PATH 中的新可执行文件。例如,在安装新软件包后,/usr/bin/ 中的文件不会立即或自动包含在补全中。因此,要包含这些新可执行文件,需要运行:

$ rehash

此 'rehash' 可以设置为自动发生。[3] 只需在您的 zshrc 中包含以下内容:

~/.zshrc
zstyle ':completion:*' rehash true

按需 rehash

同上,但 pacman 可以通过 hooks 配置以自动请求 rehash,这样就不会像上面那样产生持续 rehash 的性能损失。要启用此功能,请创建 /etc/pacman.d/hooks 目录和 /var/cache/zsh 目录,然后创建一个 hook 文件:

/etc/pacman.d/hooks/zsh-rehash.hook
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Path
Target = usr/bin/*
[Action]
Depends = zsh
When = PostTransaction
Exec = /usr/bin/install -Dm644 /dev/null /var/cache/zsh/pacman

这会使文件 /var/cache/zsh/pacman 的修改日期与上次安装、升级或删除软件包的时间保持一致。然后,需要将 zsh 引导到在命令缓存过时时进行 rehash,方法是将以下内容添加到您的 ~/.zshrc

~/.zshrc
zshcache_time="$(date +%s%N)"

autoload -Uz add-zsh-hook

rehash_precmd() {
  if [[ -a /var/cache/zsh/pacman ]]; then
    local paccache_time="$(date -r /var/cache/zsh/pacman +%s%N)"
    if (( zshcache_time < paccache_time )); then
      rehash
      zshcache_time="$paccache_time"
    fi
  fi
}

add-zsh-hook -Uz precmd rehash_precmd

如果 precmd 钩子在 /var/cache/zsh/pacman 更新之前触发,则在启动新提示符之前可能无法使用补全。运行一个空命令,例如按 Enter 键,应该就足够了。

使用 SIGUSR1 的替代按需 rehash

同上,但 hook 文件如下所示:

/etc/pacman.d/hooks/zsh-rehash.hook
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Path
Target = usr/bin/*

[Action]
Depends = zsh
Depends = procps-ng
When = PostTransaction
Exec = /usr/bin/pkill zsh --signal=USR1
警告 这会将 SIGUSR1 发送到所有正在运行的 zsh 实例。请注意,SIGUSR1 的默认行为是终止,因此当您首次配置此功能时,所有正在运行的 zsh 实例 (包括登录 Shell) 将终止,如果它们没有 sourced 下面的 trap 的话。
~/.zshrc
TRAPUSR1() { rehash }

上面的 function trap 可以替换为 list trap trap 'rehash' USR1。有关 trap 类型之间的差异,请参阅 zshmisc(1) § Trap Functions

此方法将立即 rehash 所有 zsh 实例,无需按 Enter 键触发 precmd

将按键绑定到 ncurses 应用程序

将 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

文件管理器按键绑定

像图形文件管理器中使用的按键绑定可能会很有用。第一个返回到目录历史记录 (Alt+Left),第二个让用户转到父目录 (Alt+Up)。它们还会显示目录内容。

~/.zshrc
cdUndoKey() {
  popd
  zle       reset-prompt
  print
  ls
  zle       reset-prompt
}

cdParentKey() {
  pushd ..
  zle      reset-prompt
  print
  ls
  zle       reset-prompt
}

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

xterm 标题

如果您的终端模拟器支持,您可以从 Zsh 设置其标题。这允许动态更改标题以显示有关 Shell 状态的相关信息,例如显示用户名和当前目录或当前正在执行的命令。

xterm 标题使用 xterm 转义序列操作系统命令 \e]2;\a\e]2;\e\\ 设置。例如:

$ print -n '\e]2;My xterm title\a'

会将标题设置为:

My xterm title

一种设置动态标题的简单方法是在 precmdpreexec 钩子函数中设置标题。有关可用钩子函数及其描述的列表,请参阅 zshmisc(1) § Hook Functions

使用 print -P,您可以额外利用 Zsh 的提示符转义字符。

提示
  • 只要是连续的,标题打印就可以分成多个命令。
  • GNU Screen 将 xterm 标题发送到 hardstatus (%h)。如果您想使用 Screen 的 字符串转义 (例如用于颜色),则应使用 \e_\e\\ 转义序列来设置 hardstatus。否则,如果 \e]2;\a 中使用了字符串转义,终端模拟器将收到损坏的标题,因为它无法解释 Screen 的字符串转义。
  • 不要在打印变量时使用 print-P 选项,以防止它们被解析为提示符转义字符。
  • 打印变量时使用 q 参数扩展标志,以防止它们被解析为转义序列。
~/.zshrc
autoload -Uz add-zsh-hook

function xterm_title_precmd () {
	print -Pn -- '\e]2;%n@%m %~\a'
	[[ "$TERM" == 'screen'* ]] && print -Pn -- '\e_\005{2}%n\005{-}@\005{5}%m\005{-} \005{+b 4}%~\005{-}\e\\'
}

function xterm_title_preexec () {
	print -Pn -- '\e]2;%n@%m %~ %# ' && print -n -- "${(q)1}\a"
	[[ "$TERM" == 'screen'* ]] && { print -Pn -- '\e_\005{2}%n\005{-}@\005{5}%m\005{-} \005{+b 4}%~\005{-} %# ' && print -n -- "${(q)1}\e\\"; }
}

if [[ "$TERM" == (Eterm*|alacritty*|aterm*|foot*|gnome*|konsole*|kterm*|putty*|rxvt*|screen*|wezterm*|tmux*|xterm*) ]]; then
	add-zsh-hook -Uz precmd xterm_title_precmd
	add-zsh-hook -Uz preexec xterm_title_preexec
fi

终端模拟器标签页标题

某些终端模拟器和多路复用器支持设置标签页标题。转义序列取决于终端:

Terminal 转义序列 描述
GNU Screen \ek\e\\ Screen 的窗口标题 (%t)。
Konsole \e]30;\a Konsole 的标签页标题。

Shell 环境检测

有关检测 Shell 环境的测试,请参阅 shell-environment-detection 仓库。这包括登录/交互式 Shell、Xorg 会话、TTY 和 SSH 会话。

/dev/tcp 等效:ztcp

使用 zsh/net/tcp 模块

$ zmodload zsh/net/tcp

您现在可以建立 TCP 连接:

$ ztcp example.com 80

有关更多详细信息,请参阅 zshmodules(1) § THE_ZSH/NET/TCP_MODULEzshtcpsys(1)

在部分命令行时退出 Shell 的快捷方式

默认情况下,如果命令行已填充,Ctrl+d 不会关闭您的 Shell,这可以解决这个问题:

.zshrc
exit_zsh() { exit }
zle -N exit_zsh
bindkey '^D' exit_zsh

pacman -F "command not found" 处理程序

pacman 包含搜索包含文件的软件包的功能。当执行未知命令时,以下 command-not-found 处理程序将直接使用 pacman 搜索匹配的软件包。

~/.zshrc
...
function command_not_found_handler {
    local purple='\e[1;35m' bright='\e[0;1m' green='\e[1;32m' reset='\e[0m'
    printf 'zsh: command not found: %s\n' "$1"
    local entries=(
        ${(f)"$(/usr/bin/pacman -F --machinereadable -- "/usr/bin/$1")"}
    )
    if (( ${#entries[@]} ))
    then
        printf "${bright}$1${reset} may be found in the following packages:\n"
        local pkg
        for entry in "${entries[@]}"
        do
            # (repo package version file)
            local fields=(
                ${(0)entry}
            )
            if [[ "$pkg" != "${fields[2]}" ]]
            then
                printf "${purple}%s/${bright}%s ${green}%s${reset}\n" "${fields[1]}" "${fields[2]}" "${fields[3]}"
            fi
            printf '    /%s\n' "${fields[4]}"
            pkg="${fields[2]}"
        done
    fi
    return 127
}
...
注意 pacman 的文件数据库与普通同步数据库是分开的,需要使用 pacman -Fy 来获取。有关详细信息,请参阅 pacman#Querying package databases

有关使用 pkgfile 的替代方案,请参阅 #pkgfile "command not found" handler

使用按键绑定清除后缓冲区

默认情况下,清除屏幕的按键绑定在大多数终端模拟器上不会清除后缓冲区 (您需要向上滚动才能看到的部分)。可能的解决方案如下。

~/.zshrc
...
function clear-screen-and-scrollback() {
    printf '\x1Bc'
    zle clear-screen
}

zle -N clear-screen-and-scrollback
bindkey '^L' clear-screen-and-scrollback
...

第三方扩展

配置框架

注意 框架引入了抽象和复杂性。它们可以,并且经常会,引入未定义的行为。在 Shell 损坏的情况下,*首要* 的调试步骤应该是恢复到纯 Shell。
  • oh-my-posh — Oh My Posh 是一个自定义提示符引擎,适用于任何能够通过函数或变量调整提示符字符串的 Shell。
https://github.com/JanDeDobbeleer/oh-my-posh || oh-my-poshAUR
  • oh-my-zsh — 一个流行的、社区驱动的 Zsh 配置管理框架。它捆绑了大量有用的函数、助手、插件和主题。
https://github.com/ohmyzsh/ohmyzsh || oh-my-zsh-gitAUR
  • Prezto — 一个 Zsh 的配置框架。它带有模块,通过合理的默认设置、别名、函数、自动补全和提示主题来丰富命令行界面环境。
https://github.com/sorin-ionescu/prezto || prezto-gitAUR
  • ZIM — 一个具有极速和模块化扩展的配置框架。Zim 非常易于定制,并提供了一套丰富的模块和功能,同时不牺牲速度或功能。
https://github.com/zimfw/zimfw || zsh-zim-gitAUR

插件管理器

  • Antidote — 遗留的 Antibody 插件管理器的功能齐全的 Zsh 实现。
https://github.com/mattmc3/antidote || zsh-antidoteAUR
  • zinit (以前称为 "zplugin") — 灵活的 Zsh 插件管理器,具有干净的 fpath、报告、补全管理、涡轮模式 已恢复
https://github.com/zdharma-continuum/zinit || zinitAUR
  • zi (以前称为 "zplugin") — zplugin 的替代分支,旨在扩展原始项目,而不是像 zinit 那样保留和维护原始项目。
https://github.com/z-shell/zi || 未打包? 在 AUR 中搜索
  • sheldon — 快速、可配置的 Shell 插件管理器,用 Rust 编写 [4]
https://github.com/rossmacarthur/sheldon || sheldon
  • Antigen — Zsh 的插件管理器,受 oh-my-zsh 和 vundle 启发。 已放弃
https://github.com/zsh-users/antigen || antigen-gitAUR
  • zgen — Zsh 的轻量级简单插件管理器。 已放弃
https://github.com/tarjoilija/zgen || zgen-gitAUR
  • zplug — Zsh 的下一代插件管理器。 已放弃
https://github.com/zplug/zplug || zplugAUR

类似 Fish 的语法高亮和自动建议

Fish 提供了非常强大的 Shell 语法高亮和自动建议。要在 Zsh 中同时使用它们,您可以安装 zsh-syntax-highlightingzsh-autosuggestions,最后在您的 zshrc 文件末尾 source 一个或两个提供的脚本,确保 zsh-syntax-highlightingzsh-autosuggestions 之后 [5]

~/.zshrc
source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

pkgfile "command not found" 处理程序

pkgfile 包含一个 Zsh 脚本文件,该文件提供了一个 command_not_found_handler 函数,当输入一个无法识别的命令时,它将自动搜索 pkgfile 数据库。

您需要 source 该脚本才能启用它。例如:

~/.zshrc
source /usr/share/doc/pkgfile/command-not-found.zsh
注意 在此功能工作之前,可能需要更新 pkgfile 数据库。有关详细信息,请参阅 pkgfile#Installation

对于使用 pacman 原生功能来实现相同目的的替代方法,请参阅 #pacman -F "command not found" handler

故障排除

IOT 指令

IOT instruction 消息仅表示应用程序因信号 6 (SIGABRT, Signal Abort) 而退出。此 补丁 已经包含在主线(即您可以使用 zsh-gitAUR)中,并且将在 5.10 版本中应用。有关更多信息,请参阅 [6][7]signal(7) § Standard signals

参见