在不借助oh-my-zsh的前提下进行Zsh配置

Windows(MSYS2)或Arch Linux平台下Zsh的配置

Posted by 星外之神 on June 24, 2022
本文字数:5875

前言

Linux下最常用的Bash发布于1989年,在此后的发展中并没有引入太多么革命性的功能,已经是一款十分古老的Unix Shell了。虽然它仍然是众Linux发行版预装最多的Shell,但是它的扩展性也早已不如其他的Shell。

Zsh、Fish甚至从Windows下发展而来的PowerShell相较Bash而言都极具扩展性。其中,只有Zsh能够很好地兼容Bash的语法,所以,将Zsh作为Bash的替代品非常合适。

然而,Zsh虽然可扩展性高,功能强大,但是它的配置并不容易。一般来说,要方便地配置Zsh需要借助oh-my-zsh这个强大的工具。但oh-my-zsh这个工具主要用Shell脚本写成,性能并不出色,往往需要较长的启动时间。

由于Linux下有十分成熟的内存缓存机制,因此当oh-my-zsh在系统启动后完成过一次加载,之后便可以直接从内存中读取已经缓存的内容,能够做到瞬间启动。然而,Windows下的内存缓冲机制则没有这么友好,如果使用oh-my-zsh,Zsh的加载时间将会特别长。此外,由于Windows下的Unix Shell环境均是移植而来,利用了Cygwin或衍生库将Unix API Calls转化为Windows API Calls,有显著的性能损失,对于Unix的fork()API转化效率尤其低下,再加上无论是Cygwin还是MSYS2都将Unix Shell内置的echo[等功能拆分成了独立.exe文件,增加了调用性能开销(不过WSL的原生实现可能要好一点)。因此,在Windows下使用本来就比较吃资源的oh-my-zsh十分卡顿,体验并不好。

准备

考虑到有的读者可能对Windows下的终端配置不熟悉,在这里我简单列出一下Windows下安装Zsh的方法。

由于WSL对Windows本身的交互并不是很方便,里面的工具链也不能用来构建Windows本地应用,我在这里推荐使用MSYS2。MSYS2相当于Windows版的Pacman包管理器,不仅与Arch Linux系发行版的包管理命令完美兼容,而且包构建方便(只需要写一份PKGBUILD)、官方源中软件丰富,包含了gcc、clang等编译器与众多库,还有ffmpeg等基础软件和VLC等方便的用户端GUI软件,功能十分强大。

MSYS2已经包含在了winget的软件库中,可以直接通过命令安装:

winget install msys2.msys2

安装完成后,需要在系统环境变量(现在的Windows系统应该只需要在开始菜单的搜索框中输入path就能弹出)中添加如下变量:

变量名 变量值
MSYS2_PATH_TYPE1 inherit

其实也可以把MSYS2的相关路径(使用的MinGW-w64工具链路径MSYS2安装路径/使用的MinGW类型/bin以及MSYS2路径MSYS2安装路径/usr/bin)添加到Path变量中,方便直接在Windows的cmd或者PowerShell中调用MSYS2命令,但是据说可能会出现一些冲突,然而笔者添加了以后并没有发现什么问题,因此这也可以作为一个可选项。

  • 将MSYS2的相关可执行文件路径添加到系统环境变量的一个示例:
Path变量中添加的内容2
D:\msys64\ucrt64\bin3
D:\msys64\usr\bin3

添加完成后,在MinTTY中运行MSYS2终端(如果添加了MSYS2可执行文件路径到Path环境变量,也可以在Windows终端的PowerShell或cmd环境中执行),安装Zsh:

pacman -S zsh

为了方便,可以将MSYS2集成到Windows终端,在Windows终端中选择添加新配置文件-新建空配置文件,在命令行中填入:

cmd.exe /c set MSYSTEM=你使用的MinGW环境名称 && set CHERE_INVOKING=enabled_from_arguments && MSYS2安装位置/usr/bin/
zsh.exe --login

例如:

cmd.exe /c set MSYSTEM=UCRT64 && set CHERE_INVOKING=enabled_from_arguments && D:/msys64/usr/bin/
zsh.exe --login

以上命令依靠在cmd中配置MSYS2所需的特殊环境变量,再启动Zsh,如果不想这样手动写出要加载的环境变量,也可以直接调用MSYS2的cmd,只需要在Windows终端中选择添加新配置文件-新建空配置文件,在命令行中填入:

你的MSYS2安装路径\msys2_shell.cmd -对应使用的MinGW环境(如-mingw64) -here -no-start -full-path -defterm -shell zsh

例如:

D:\msys64\msys2_shell.cmd -ucrt64 -here -no-start -full-path -defterm -shell zsh

oh-my-zsh的替代实现

oh-my-zsh提供的便利主要是主题支持和插件支持,当然还有其他的操作绑定。这些我们都可以想办法去进行性能更优的替代实现。

主题支持及状态提示

在oh-my-zsh的启发下,Jan De Dobbeleer开发了一个功能较为接近的oh-my-posh。与oh-my-zsh不同,oh-my-posh采用Go语言开发,虽然运行效率仍然较C/C++低不少,但是其性能仍然显著高于直接用Sell写成的oh-my-zsh。

虽然oh-my-posh从名称来看好像是为微软的PowerShell专门设计,但是由于它并没有用绑定在Shell上的语言实现,故实际上oh-my-posh支持多种Shell环境,当然也包括Zsh。

oh-my-posh不仅是跨Shell的,它还是跨平台的,Windows与Acrhlinux系发行版均可以很方便地安装,Windows安装命令如下:

winget install JanDeDobbeleer.OhMyPosh

Arch Linux系发行版则是(使用yay):

sudo yay -S oh-my-posh-bin

预览

Zsh需要有对应的.zshrc文件才能正常启动,在正式配置流程开始之前,我们不妨先让Zsh自动建立一个无功能的初始化.zshrc文件:

#~/img/首次运行Zsh.webp
首次运行Zsh

如上图所示,在没有配置文件时首次运行Zsh会输出以上提示。为了有一个供后续配置的输入环境,我们可以在这里输入0,输入cat ~/.zshrc后可以看到,程序在此处生成了一个空的配置文件:

$ cat ~/.zshrc
> # Created by newuser for 5.8

oh-my-posh在不同平台的文件位置有些区别,在Zsh中预览效果时,Windows下可以执行:

# $POSH_THEMES_PATH路径在安装时已经添加到了环境变量中
eval "$(oh-my-posh init zsh --config $POSH_THEMES_PATH/想要使用的主题文件)"

Arch Linux下执行:

eval "$(oh-my-posh init zsh --config /usr/share/oh-my-posh/themes/想要使用的主题文件)"

具体的主题样式预览参见oh-my-posh官网,可以从中选择自己喜欢的主题,oh-my-posh项目推荐使用的是jandedobbeleer.omp.json这款主题。

如果配置成功,就会显示界面:

#~/img/预览中的oh-my-posh主题效果.webp
预览中的oh-my-posh主题效果

这里我们可以发现,系统并没有自带oh-my-posh主题所需要的字体,部分字符被显示成了方块,这一问题我们稍后再解决。

oh-my-posh可不仅仅是一个主题管理器,它还自带了命令运行计时、Git仓库管理提示等功能,因此这些Zsh插件不再需要我们安装了。

下载安装Zsh相关功能插件

Zsh具有许多能够提高生产力的插件,如自动补全插件、语法高亮插件等。

对于Arch Linux,这些插件都已经集成到了软件源中,可以直接安装:

yay -S zsh-syntax-highlighting zsh-autosuggestions zsh-history-substring-search

对Windows则较为麻烦,需要手动clone到本地:

mkdir ~/.zsh-config
cd ~/.zsh-config
git clone https://github.com/zsh-users/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git
git clone https://github.com/zsh-users/zsh-history-substring-search.git

编写.zshrc文件

.zshrc是Zsh的配置文件,没有了oh-my-zsh,我们需要手动进行编写。

  • 首先需要在Zsh运行时指定oh-my-posh主题,添加:
eval "$(oh-my-posh init zsh --config 主题文件路径)"
  • 为了自动保存历史,我们还需要指定历史记录文件地址及读取、写入配置:
HISTFILE=~/.zsh_history
HISTSIZE=100000000                  # 设置历史记录读取行数
SAVEHIST=100000000                  # 设置历史记录读取行数

setopt BANG_HIST                    # 在展开字符期间对"!"特殊处理
setopt EXTENDED_HISTORY             # 生成详细的历史记录
setopt INC_APPEND_HISTORY           # 立即写入历史文件,而不是退出时写入
setopt SHARE_HISTORY                # 在各个终端窗口中共享历史记录
setopt HIST_EXPIRE_DUPS_FIRST       # 修剪掉过量的历史记录时首先去重复
setopt HIST_IGNORE_DUPS             # 不记录刚刚记录的内容
setopt HIST_IGNORE_ALL_DUPS         # 如果新内容重复,则删除旧内容
setopt HIST_FIND_NO_DUPS            # 不显示先前查找到的历史记录内容
setopt HIST_IGNORE_SPACE            # 不记录以空格开头的内容
setopt HIST_SAVE_NO_DUPS            # 不要在历史文件中写入重复的条目
setopt HIST_REDUCE_BLANKS           # 在记录条目之前删除多余的空白
setopt HIST_VERIFY                  # 在显示历史扩展时不要立即执行
setopt HIST_BEEP                    # 访问不存在的历史记录时发出声音提示
  • 加载之前下载的插件(这里用的是Windows按照本文方法下载的路径,Arch Linux替换为对应的安装路径即可):
source ~/.zsh-config/zsh-autosuggestions/zsh-autosuggestions.zsh                    # 加载自动补全插件
source ~/.zsh-config/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh            # 加载语法高亮插件
source ~/.zsh-config/zsh-history-substring-search/zsh-history-substring-search.zsh  # 加载历史搜索插件
  • 最后可以根据习惯指定相关快捷键绑定,比如搜索历史记录、逐词跳过等:
bindkey "^[[A" history-substring-search-up      # Up 设置向前查找与此相关
bindkey "^[[B" history-substring-search-down    # Down 设置向后查找与此相关
bindkey ";5A" history-beginning-search-backward # Ctrl-Up 向前查找以此开头
bindkey ";5B" history-beginning-search-forward  # Ctrl-Down 向后查找以此开头
bindkey ";5C" emacs-forward-word                # Ctrl-Right 向前跳过一个单词
bindkey ";5D" emacs-backward-word               # Ctrl-Left 向后跳过一个单词
bindkey "\e[3~" delete-char                     # Del键 删除后面的一个字符

编辑.zshrc时应当注意.zshrc中配置项的逻辑顺序:

  • bindkey调用了历史记录子字符串查找插件,所以该插件必须在相关bindkey之前加载
  • 历史记录子字符串查找插件会自动高亮标出正在搜索的字串,这一语法高亮优先级应当高于一般基于命令本身的语法高亮,因此语法高亮插件应当在历史子字符串插件加载前加载

字体配置

oh-my-posh工具依赖Nerd Fonts字体,在Arch Linux下可以直接在Archlinuxcn源中下载nerd-fonts-noto字体:

sudo pacman -S nerd-fonts-noto

Windows下则需要手动下载并安装,官方推荐的字体是Meslo LGM NF,下载后解压并右键点击,选择为所有用户安装(避免Windows终端无法识别字体)。

安装完成后,在终端中切换到对应的Nerd Front字体即可,安装成功后,配置了oh-my-posh主题的Zsh便不再乱码。

#~/img/oh-my-posh配置好字体以后的显示情况.webp
配置好字体以后的显示情况

Arch Linux下的最简方法

我已经将这个简单的.zshrc文件打包并推送到了AUR,大大简化了安装流程,现在Arch Linux下安装只需要:

yay -S easy-zsh-config

然后再复制配置文件即可使用:

cp /etc/zsh/zshrc ~/.zshrc

安装完成后可以使用chsh /bin/zsh来切换默认Shell环境。

目前AUR中的oh-my-posh-bin存在权限设置bug,可能会导致oh-my-posh的主题设置失败,可以执行以下命令解决这一问题:

sudo chmod -R +r /usr/share/oh-my-posh/themes/
  1. 指定MSYS2程序读取的环境变量类型,inherit表示将系统变量合并到MSYS2环境变量 

  2. 注意不要删除Path变量中的原有内容 

  3. 注意应当写成本地MSYS2可执行文件目录所在路径或本地使用的MSYS2的MINGW环境的所在路径,且应当保证MINGW环境的所在路径排在前面  2