Day 07:我今天想不到标题之整合 tmux 和 zsh

我把从第一天到现在每天的 Home 目录都放上 GitHub 了,README.md 里面有说明
这是今天的 Release https://github.com/simba-fs/2021-ironman-example/releases/tag/day07


昨天的结尾提到要整合 tmux 和 zsh 不是在 ~/.zshrc 结尾执行 tmux 这麽简单,今天就让我们看看会遇到什麽问题吧!

直接执行 tmux

在正式开始前,先让我们看看直接~/.zshrc 後面执行 tmux 会发生什麽错误

tmux 1
直接执行 tmux

嗯,错误讯息说要 unset $TMUX 那我们就照作吧!

tmux reproduce
加上 unset TMUX,嗯,爆炸了!

分析问题

可以看到,如果直接执行 tmux 的话总是会跳出一个错误 sessions should be nested with care, unset $TMUX to force,这段讯息告诉我们,不能建立巢状 tmux,除非将 $TMUX 环境变数移除。欸?我们不是只执行一次 tmux 吗?为什麽会他说我们建立巢状 tmux?我们来看看登入之後发生了什麽事:

  1. 执行 zsh(因为我们的 default shell 是 zsh)
  2. zsh 执行 ~/.zshrc,初始化终端机後执行 tmux
  3. tmux 开启了新的 session执行 default shell
  4. ~/.zshrc 又被执行一次,tmux 被执行第二次
  5. 如果你没有 unset TMUX,那 tmux 就会停下来并印出错误讯息,你总共得到两层 tmux
    如果你 unset TMUX,就是告诉 tmux 不管巢状限制,就会回到第三步,你等越久会得到越多 tmux

看来问题在於 tmux 和 zsh 执行的回圈停不下来,那我们就在执行 tmux 之前作个条件判断,$TMUX 为空再执行 tmux 好了

❓ > $TMUX 是什麽
$TMUX 是一个环境变数,是一个由三个部份串起来、以逗号分开的字串,第一部份是 tmux 的 unix socket 路径,第二部份是 tmux 的 pid,最後是目前 tmux window 的编号(左下角那个数字)。这个环境变数只有在 tmux 里面的 session 会设定,所以可以当作 tmux 是否启动的检查

初步修改

我们在 ~/.zshrc 中执行 tmux 的那行做一些修改

+ if [[ -z $TMUX ]];then
tmux
+ fi

提示:-z $TMUX$TMUX == "" 效果是一样的

接下来我们看看这样修改效果如何

tmux 2
先检查 $TMUX 再执行 tmux

可以看到,巢状 tmux 的算是问题解决了,但是你会发现离开 tmux 之後还是一个完整的 zsh,但是这时候你已经结束工作了,不需要再一个 shell,你希望关掉 tmux 之後应改关掉终端机视窗的,这又要怎麽办呢?

关掉多余的 zsh

题外话,从这里开始就是个人龟毛,想要把使用体验调整到最好

这里介绍一个内建指令 exec,这个指令会把当作的 shell 用後面的执行档替换掉。例如我们现在的 shell 是 zsh,执行 exec ssh [email protected] 之後,我们的 shell 就会换成 ssh 了。这有什麽好处?简单来说就是离开这个指令後就会离开终端机,不会再回到原本的 shell。这个效果刚好和我们的需求是一样的,所以要解决多余的 zsh,就只需要在 tmux 前面加上 exec

if [[ -z $TMUX ]];then
- tmux
+ exec tmux
fi
❓ > exec cmdcmd; exit 有什麽不一样
这两个写法都会有一样的效果 —— 结束 cmd 後离开,但是他们达成的原因不同,详细叙述在 stackover flow 有相关讨论,有兴趣可以看看
你有可以用 htop 之类的工具看看 process 的结构,你就会知道 execexit 差别在哪了

改进 ~/.zshrc

我们回头看看目前的 shell 启动流程,你会发现虽然我们不会回到最初的 zsh,但是他却做了一堆无意义的初始化、外挂载入,我们可以将这段设定纳入 if 里面,需要时才执行,如果只是要启动 tmux 就不必走一遍设定 plugin 之类的流程,改进後的 ~/.zshrc 大概长这样

if [[ -z $$TMUX ]]; then
    exec tmux
else
    # init zsh ......
fi

如此一来载入速度和记忆体用量都会有一咪咪的减少

选择性执行 tmux

有时候你可能会不想启动 tmux,例如 ssh 到远端主机,在远端主机上启动 tmux 而不是在本机上启动(在本机上启动的话要开很多 ssh 连线,在远端启动只要连线一次),这时候就要有一个机制可以把主机上的 tmux 关掉,回到原本的 shell,达成方法有很多,这里我介绍一个我觉得最优雅的方法,在 ~/.zshrc 中 tmux 启动判断上加上以下条件

- if [[ -z $TMUX ]]; then
+ if [[ -z $TMUX ]] && [[ ! -f $HOME/.notmux  ]]; then

这时候 tmux 启动条件就变成「tmux 还没启动」且「~/.notmux 不存在」,在这里我们把 ~/.notmux 这个档案当作一个开关,如果这个档案存在 tmux 就不会启动。

如果你想启动一个没有 tmux 的终端机,先建立 ~/.notmux 档案 touch ~/.notmux,然後开启新的终端机

结尾

今天的内容比较杂,修改的部份也比较零散,下面是目前 ~/.zshrc 的内容

if [[ -z $TMUX ]] && [[ ! -f $HOME/.notmux  ]]; then
    exec tmux
else
    source ~/.zplug/init.zsh
    
    # plugins
    zplug 'romkatv/powerlevel10k', as:theme, depth:1
    zplug 'zsh-users/zsh-autosuggestions'
    zplug 'marlonrichert/zsh-autocomplete'
    zplug 'hlissner/zsh-autopair'
    
    if ! zplug check --verbose; then
        printf "Install? [y/N]: "
        if read -q; then
            echo; zplug install
        fi
    fi
    
    zplug load
    
    # Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
    # Initialization code that may require console input (password prompts, [y/n]
    # confirmations, etc.) must go above this block; everything else may go below.
    if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
      source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
    fi
    # To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
    [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
    
    if [[ -z $TMUX ]]; then
        tmux
        exit
    fi
fi

这篇文不小心断更了,呜呜呜,这里是我新的新开的文章系列 https://ithelp.ithome.com.tw/users/20130473/ironman/4804


<<:  ASP.NET MVC 从入门到放弃(Day2) -Visual Studio 2019 专案建立

>>:  WordPress 如何引用 Bootstrap 的 CSS 及 JS 档案制作精美画面

Day20 探讨setting(2)

昨天介绍到SECRET_KEY,不晓得前一天的东西大家有没有完全了解了呢! 那今天我们再来接着继续介...

Day22 - Ajax 加上 Antiforgery Token (二)

Case01 与 Day21 重点差异的部份: Controller 内 Action: 加上 Va...

Day26 Java String(Ⅰ)

String类提供了1.equals() 2. equalsIgnoreCase()方法来比较两个字...

【资料结构】前中後运算式转置

前中後运算式转置 中置运算式是人脑的计算中最直观且最习惯理解的表示式,会将运算子(EX:加号)放在两...

【Day 10】Repository 设计模式(Python)

前言 Repository 设计模式主要是要分离商业逻辑与资料存取的逻辑,希望开发者专注在商业逻辑的...