Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS 终端美化与 zsh 多设备配置同步共享 #28

Open
toFrankie opened this issue Feb 25, 2023 · 0 comments
Open

macOS 终端美化与 zsh 多设备配置同步共享 #28

toFrankie opened this issue Feb 25, 2023 · 0 comments
Labels
2022 2022 年撰写 Mac 与 Mac、macOS 相关的文章 Terminal 与 Terminal 相关的文章

Comments

@toFrankie
Copy link
Owner

toFrankie commented Feb 25, 2023

配图源自 Freepik

前言

由于个人对 iTerm2 等第三方终端工具不太感冒,因此一直在用系统内置终端。相比那些花里胡哨的东西,系统自带的 Terminal 可谓是简陋啊。

今天,终于有空折腾一下它了,默认长这样 👇

为什么要使用 zsh?

在 Unix-like 操作系统中供选择的 Shell 解析器种类有很多,最常见的是 bash 和 zsh。

相较之下,zsh 主要有以下优点:

  • 完全兼容 bash,因此 !# /bin/bash 这类脚本也是完美支持的。
  • 更强大的 Tab 补全。
  • 更智能的目录切换。
  • 命令选项补全。
  • 文件、目录大小写自动更正(最最最直观的感受,太方便了)。
  • 丰富的主题、插件(Oh My Zsh)
  • 可查看命令输入历史记录。

总的来说,Tab 大法好,有事没事 Tab 一下,可以帮你省掉很多命令的输入。

自 macOS 10.15 起,系统使用 zsh 作为默认 Shell。如果你还在用 bash,可参考「在 Mac 上将 zsh 用作默认 Shell」一文进行迁移。

Oh My Zsh

zsh 的功能很多,但是配置较为繁琐,详细配置请看 Archlinux Zsh

但是,Robby Russell 开发的 Oh My Zsh 项目极大地改变了配置繁琐的现象,而且带来了强大的插件和主题功能。

安装

$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

安装完成后,它被存放于 ~/.oh-my-zsh 目录,在里面我们可以找到它提供的任何插件、主题等。

需要注意的是,此前的 ~/.zshrc 配置文件会被重命名为 ~/.zshrc.pre-oh-my-zsh。若有需要,可将此前的配置重新添加到 ~/.zshrc 里面。

启用插件

Oh My Zsh 提供的插件很多很多很多,详见 Plugins Wiki。如需启用某插件,只需在 ~/.zshrc 引入即可。多个插件之间使用「空白符」隔开,但不能用逗号 , 隔开,否则会被中断。

举个例子,以下将会按顺序启用 nvm、git、ruby 插件。

plugins=(nvm git ruby)

切换主题

Oh My Zsh 提供了超过 150 种主题,默认主题是 robbyrussell,详见 Themes Wiki。同样地,如需配置主题,则添加到 ~/.zshrc 里面。

ZSH_THEME="robbyrussell"

它还提供了一些花里胡哨的配置,比如随机主题。

# 每打开一个新的 Shell 窗口,随机选择内置的主题。
ZSH_THEME="random"

# 或者从多个候选主题中随机展示。
ZSH_THEME_RANDOM_CANDIDATES=(
  "robbyrussell"
  "agnoster"
)

# 甚至可以排除掉不喜欢的主题,这样就不会在随机主题中出现。
ZSH_THEME_RANDOM_IGNORED=(pygmalion tjkirch_mod)

Terminal Theme

系统内置的终端工具默认主题「Basic」是白底黑字的。虽然也内置了几种主题供选择,但架不住它丑啊。

修改命令提示符

PROMPT="%(?:%{$fg_bold[green]%}→ ●:%{$fg_bold[red]%}→ ●)%{$fg_bold[white]%}●"
PROMPT+=" %{$fg_bold[yellow]%}%c %{$reset_color%}$ "
RPROMPT="[%{$fg[white]%}%*%{$reset_color%}]"

如果系统是浅色模式,此时 vim 背景色仍然是白底,可以在 ~/.vimrc 中添加以下配置,这样主题就都统一了。

set background=dark "设置背景色

最终效果 👇

详见:terminal-dark-theme ⭐️

配置同步

由于我这边有 MacBook Pro 和 iMac 两个设备,那么设备间同步就显得很重要了,可以省去修改其一设备配置,需要拷贝到另一设备以同步更新的麻烦。

首先,我们的 zsh 配置都是用户级别的,也就是存放在 ~ 目录下:

~/.zshrc

如何做配置同步共享呢?

思路非常简单:

  1. 将配置文件存放于 iCloud 云盘,可多设备同步。
  2. 在本地配置中引入 iCloud 云盘同步的配置文件。

首先,我们在 iCloud 云盘创建一个目录,比如 Terminal

$ cd ~/Library/Mobile\ Documents/com~apple~CloudDocs
$ mkdir Terminal

然后,将 ~/.zshrc 拷贝至 Terminal 目录,并重命名为 zshrc.sh

$ cp ~/.zshrc ~/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc.sh

以上创建目录、拷贝、重命名等操作可直接在 Finder 中完成。

接着,修改本地的 ~/.zshrc,可以移除掉里面原先的配置,然后写入一行配置即可:source $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc.sh,可直接使用以下命令完成:

$ echo 'source $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc.sh' > ~/.zshrc

所以 ~/.zshrc 配置文件就变成了:

source $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc.sh

source 命令用于执行一个脚本,通常用于重新加载一个配置文件。

最后,刷新下 ~/.zshrc 配置文件。

$ source ~/.zshrc

在其他设备下,只要修改一次本地配置文件,并刷新配置即可。

配置拆分

前面做配置同步的初衷是解决多设备的场景,另一方面是可以做备份,下次换机器可省去配置的麻烦。

既然是多设备,那极有可能各设备的环境是不一样的,也就是配置会有所不同。基于此场景,直接采用上述方式显然是不妥的。假设设备 A 安装了 nvm,然后在 iCloud 云盘 Terminal/zshrc.sh 里添加了对应的配置,而设备 B 是没有安装 nvm 的,但由于 B 共享了配置,在 B 设备中执行 souce ~/.zshrc 就会导致出错。

因此,我们要对 Terminal/zshrc.sh 配置进行拆分:

~/Library/Mobile Documents/com~apple~CloudDocs/Terminal/
├── zshrc.sh            # 统一引入以下细分配置
├── zshrc-common.sh     # 各设备共同配置,比如 Oh-My-Zsh 的一些配置等
├── zshrc-imac.sh       # iMac 设备特有配置
└── zshrc-mbp.sh        # MacBook Pro 设备特有配置 

👆 以上按自个实际情况拆分。这里文件名不以 . 开头的原因是不想隐藏文件,毕竟它不存在于本地用户的主目录下,没必要隐藏了。另外,扩展名是可省略的,甚至可随意自定义。由于 ~/.zshrc 本身就是一个 Shell 脚本,而 Shell 脚本扩展名是可选的。但按习惯,多将其定义为 .sh,加之主流编辑器对此扩展名一般都有语法高亮。

按设备引入对应配置

首先,我们现在 Terminal/zshrc.sh 引入 zshrc-common.sh 共同的配置文件。

# zshrc.sh

# 加载共同配置
source $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc-common.sh

# 加载设备特有配置
# 而且应放在共同配置后面加载,原则上它们的优先级应该较高的。
# ...

接着,要解决按设备引入各自特有的配置文件。用以下几种方法来区分设备:

$ hostname
Frankies-iMac.local

$ scutil --get LocalHostName
Frankies-iMac

$ scutil --get ComputerName
Frankie's iMac

对应如下:

其中 LocalHostNameComputerName 格式化之后的名称,比如空格会替换为连字符 -,一些特殊符号也会被忽略。hostname 则是在 LocalHostName 加上 .local 的名称。但由于 hostname 读取顺序的问题(详见),它可能会受到所连接网络的影响,因此它可能不是固定值。

基于以上考虑,这里使用 scutil --get ComputerName 命令,它的返回值取决于你输入的电脑名称。但注意 ComputerName 为 macOS 独有。

接着,编写一个 Shell 函数,按设备电脑名称加载对应配置。

# 根据设备电脑名称,读取对应配置
function load_device_zsh_configuration() {
  local computer_name=$(scutil --get ComputerName)
  local icloud_config_dir="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Terminal"
  if [[ $computer_name =~ 'MacBook' ]]; then
    local config_file="$icloud_config_dir/zshrc-mbp.sh"
    if [ -f "$config_file" ]; then
      source "$config_file"
    fi
  elif [[ $computer_name =~ 'iMac' ]]; then
    local config_file="$icloud_config_dir/zshrc-imac.sh"
    if [ -f "$config_file" ]; then
      source "$config_file"
    fi
  fi
}
load_device_zsh_configuration
unset -f load_device_zsh_configuration

👆 以上几个地方按需调整。一是 icloud_config_dir 后面的目录,也就是 iCloud 云盘中存放配置文件的目录。二是类似 $computer_name =~ 'MacBook' 这行,意思是当 ComputerName 中包含 MacBook 字符串时,执行 if 语句,将加载 zshrc-mbp.sh 配置。

因此,zshrc.sh 的配置如下:

# Load zsh common configuration
source $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc-common.sh

# Load device zsh configuration
function load_device_zsh_configuration() {
  local computer_name=$(scutil --get ComputerName)
  local icloud_config_dir="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Terminal"
  if [[ $computer_name =~ 'MacBook' ]]; then
    local config_file="$icloud_config_dir/zshrc-mbp.sh"
    if [ -f "$config_file" ]; then
      source "$config_file"
    fi
  elif [[ $computer_name =~ 'iMac' ]]; then
    local config_file="$icloud_config_dir/zshrc-imac.sh"
    if [ -f "$config_file" ]; then
      source "$config_file"
    fi
  fi
}
load_device_zsh_configuration
unset -f load_device_zsh_configuration

一次失败的尝试与思考

最初,我有一种利用链接文件特性的思路:

Terminal/zshrc.sh~/.zshrc 建立硬链接关系,此时两者就是真正意义上的同一文件(inode 号码相同),修改其中一方,另一方会同步修改。而且删除任意一方,对另一方不会产生影响。

但是,由于 iCloud 云盘中的文件会进行同步操作。据我观察,当文件同步完成之后,尽管文件名不会发生改变,但 inode 号码会发生变化的。这样的话,会导致前面建立的硬链接关系破裂,即 Terminal/zshrc.sh~/.zshrc 的 inode 不再相同,修改任意一方,另一方都不会同步修改。因此,基于硬链接的思路是不行的。

然后,我又萌生了另一种思路:利用软链接文件。软链接文件的文件内容存放的是文件路径,前面 iCloud 同步不会影响文件名,因此看起来似乎是可行的:

# 创建 Terminal/zshrc.sh 的软链接至 ~/.zshrc.icloud
$ ln -s ~/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc.sh ~/.zshrc.icloud

# 在 ~/.zshrc 写入配置
$ echo 'source ~/.zshrc.icloud' > ~/.zshrc

# 刷新配置
$ souce ~/.zshrc

👆 以上在 ~/.zshrc 加载 ~/.zshrc.icloud 的时候,由于后者是 Terminal/zshrc.sh 的软链接,命令执行时会找到 Terminal/zshrc.sh 的内容进行加载。

这种方案看着是可行的,但属实有点多次一举了。何不直接在 ~/.zshrc 加载 Terminal/zshrc.sh 呢?

若对硬链接与软链接文件特效不太了解的话,可看 Linux 链接文件详解

其他

完成以上多设备同步、配置共享之后,后续配置调整,应根据实际情况对以下文件作出修改,而不是直接修改 ~/.zshrc 本地配置。

~/Library/Mobile Documents/com~apple~CloudDocs/Terminal/
├── zshrc-common.sh
├── zshrc-imac.sh
└── zshrc-mbp.sh

由于 iCloud 云盘的 Terminal 目录不好记,还长,加之容易忽略 Mobile\ Documents 空格的问题。因此,我们可以在 zshrc-common.sh 设置一些变量或别名以快速定位到配置文件。以下仅供参考:

# zshrc-common.sh

# 刷新本地配置
alias sourcez="source ~/.zshrc"

# 设置别名,可快速打开各配置文件
alias openz-common="open $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc-common.sh"
alias openz-imac="open $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc-imac.sh"
alias openz-mbp="open $HOME/Library/Mobile\ Documents/com~apple~CloudDocs/Terminal/zshrc-mbp.sh"

# 设置变量,可直接通过 `cd $ICLOUD_TERMINAL_DIR` 命令打开目录
export ICLOUD_TERMINAL_DIR="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Terminal"

这样的话,比如要往 zshrc-imac.sh 中添加配置,可以这样:

# 打开 zshrc-imac.sh 配置文件
$ openz-imac

# 往 zshrc-imac.sh 配置文件中添加一行配置:export CUR_DEVICE="Frankie's iMac"

$ 刷新配置
# soucez

# 测试一下
$ echo $CUR_DEVICE
Frankie's iMac

甚至,可以给每个配置文件设置一个变量 Configuration_File_Name,然后利用类似 echo 'some configuration' >> $Configuration_File_Name 形式往配置文件中追加配置。请自行发挥。

The end.

@toFrankie toFrankie added Mac 与 Mac、macOS 相关的文章 Terminal 与 Terminal 相关的文章 labels Feb 25, 2023
@toFrankie toFrankie added the 2022 2022 年撰写 label Apr 26, 2023
@toFrankie toFrankie changed the title Mac 系统终端美化与 ZSH 多设备配置同步共享 macOS 终端美化与 zsh 多设备配置同步共享 May 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2022 2022 年撰写 Mac 与 Mac、macOS 相关的文章 Terminal 与 Terminal 相关的文章
Projects
None yet
Development

No branches or pull requests

1 participant