跨平台一键配置终端:nushell + wezterm + oh my posh

引言

之前在各个平台上分别使用不同的终端,感觉体验上差了点意思。调研了一下支持跨平台的终端工具,最终选定了nu shell + wezterm + Oh My Posh的方案,并且使用dotfiles提供统一的配置。

基本思路

基本思路如下:

  1. 使用Git库保存和同步安装脚本和配置文件;
  2. 使用homebrew(Mac 和 Linux)或者winget(Windows)作为包管理器;
  3. 使用shell脚本执行安装。

使用环境

希望实现Windows、Mac OS和Linux(以Ubuntu为例)不同环境下终端工具的自动安装与配置,目前初步实现Windows和Mac的配置。

使用的前提条件包括:

  1. 能够科学上网或者连接GitHub;
  2. 已经安装有bash或者zsh等shell,例如在Windows上可以使用Git Bash。

脚本功能

识别系统类型

识别系统类型的目的是为了后续选择对应的安装和配置命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 判断系统类型
OS="`uname | tr A-Z a-z`"
case $OS in
linux*)
OS='Linux'
;;
freebsd*)
OS='FreeBSD'
;;
windowsnt* | mingw* | cygwin* | msys*)
OS='Windows'
;;
darwin*)
OS='Mac'
;;
sunos*)
OS='Solaris'
;;
*)
OS='Unknown'
;;
esac

安装程序

采用homebrew进行安装时,如果已经存在这个程序,安装会报错,因此可以先使用brew list判断程序是否已经安装。

nushell为例,其安装脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 判断系统类型并保存为环境变量
OS="`uname | tr A-Z a-z`"
case $OS in
linux*)
OS='Linux'
alias ls='ls --color=auto'
;;
freebsd*)
OS='FreeBSD'
alias ls='ls -G'
;;
windowsnt* | mingw* | cygwin* | msys*)
OS='Windows'
;;
darwin*)
OS='Mac'
;;
sunos*)
OS='Solaris'
;;
*)
OS='Unknown'
;;
esac

复制配置文件

与安装时类似,复制配置文件的基本步骤是判断是否存在配置文件夹,如果有先备份,如果没有先创建,然后再复制。

同样以nushell为例,其安装脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 设置 nushell 配置文件
NUSHELL_CONFIG_PATH="$(nu -c '$nu.config-path')"
NUSHELL_CONFIG_DIR=$(dirname "$NUSHELL_CONFIG_PATH")
if [ ! -d "$NUSHELL_CONFIG_DIR" ]
then
mkdir "$NUSHELL_CONFIG_DIR"
else
back_up_dir="$NUSHELL_CONFIG_DIR"/back_up_$(date +%Y_%m_%d_%H_%M_%S)
mkdir "$back_up_dir"

mv "$NUSHELL_CONFIG_DIR"/*.nu "$back_up_dir/" 2>/dev/null
fi
cp -r ./nushell/* "$(dirname "$NUSHELL_CONFIG_PATH")/"

遇到的一些坑

脚本变量的替换问题

在编写脚本的时候遇到过这样的问题:直接在终端中可以识别的变量,在脚本中无法正确获取值。后来发现是由于双引号的问题,查阅了一些资料,建议总是使用双引号对变量替换或者命令替换进行包裹。具体参见:

https://unix.stackexchange.com/questions/131766/why-does-my-shell-script-choke-on-whitespace-or-other-special-characters

shell错误继续执行

与其他常见的编程语言不同,shell脚本在遇到错误后,并不会立刻退出,而是会继续向下执行,如果前后的命令之间存在依赖关系,那么就可能会导致难以预计的错误。

一个可行的解决办法是,在执行下一条命令时判断上一条命令是否正确执行,可以采用$?返回执行的状态码。具体参见:

https://www.shellscript.sh/exitcodes.html

小结

刚开始用dotfiles这种方式来实现跨平台的工具配置,目前还比较初步,但是感觉还是不错的,尤其是有多个不同的工作环境的时候。后续有丰富再继续更新。