上次简单介绍了 tmux 的一些基本概念和用法,能让我们很快的上手使用。但想用的顺手我认为还需要做些改进。

所以,本篇主要分享自己目前在用的 tmux 配置,并附上详细说明原因,自己以后查阅也方便。

在分享前

先介绍几个概念,tmux 中有几种常见配置:

  • 快捷键(key):可以通过 bind-key 命令来配置,比如 tmux bind-key S choose-tree 意思是绑定 S 用来触发 choose-tree 这个 tmux 命令(当然,要先按 prefix key ),效果和直接再 tmux session 中输入 tmux choose-tree 是一样的。
  • 变量(option):比如 tmux set-option history-limit 10000 是设置 tmux 的历史长度

这些配置都可以放到 ~/.tmux.conf 这个文件下,tmux 第一次启动时,会加载这些配置。

在运行 tmux 时,可以通过 prefix key + :,然后输入 source-file ~/.tmux.conf 手动重新加载配置。不过呢,和 shell 一样,tmux 加载配置只是修改配置中对于的变量,对于旧的没被覆盖的配置,还是会在的。

所以有时候我会 tmux kill-server 直接杀掉 tmux 进程,再重新打开 tmux 来保证配置加载的完整性。

放一张配置完的图,也是上一篇的第一张图 tmux-sample.jpg

开始吧

开胃菜

# Common config
set-option -g set-titles on
set-option -g set-titles-string "#S / #W"

tmux 默认不会改 Terminal 的 title,所以在终端软件的 tab 名字里面只有 “tmux”,这对于同时要开很多个 tab 的人来说很不友好。所以我开启了 title ,并把它的格式改为 当前 session 名字 / 当前 window 名字

set-option -g repeat-time 1000  # default is 500

tmux 在执行连续的快捷键时(比如切换 pane ),默认只有 500ms 的等待时间,超过这个时间,就会退回到正常输入模式,有时候稍微按得慢一点(也可能是我手残),就要重新按 prefix key 来重新输入快捷键,所以我把他改为 1s

set-option -g history-limit 10000

默认的历史行数比较小,改大一点,看程序日志的时候不至于被吃掉。(有时候我会吧 tmux 当成临时的 supervisor 进程管理解决方案)

# Terminal type configuration
set-option -g default-terminal "screen-256color"
set-option -ga terminal-overrides ",xterm-256color:Tc"

tmux 中的颜色可能和 shell 中的有所偏差,使用如上设置使得颜色能正常显示。

副菜

作为 Vim 党,当然希望 tmux 中也能用到一些 Vim 类的快捷键。

set-window-option -g mode-keys vi

这样就可以在滚动模式(copy-mode)中,使用一些 Vim 键位了。

不过我觉得这还不够 Vim ,还需要进一步的设置。

# Move & Copy while scrolling
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
bind-key -T copy-mode-vi u send-keys -X halfpage-up
bind-key -T copy-mode-vi d send-keys -X halfpage-down

浏览历史的时候,可以用 v 选择,y 复制,u/d 翻页。

# Select pane
bind-key -r j select-pane -D
bind-key -r k select-pane -U
bind-key -r h select-pane -L
bind-key -r l select-pane -R

使用 j,k,h,l 来选择 pane

bind-key -r M-j resize-pane -D
bind-key -r M-k resize-pane -U
bind-key -r M-h resize-pane -L
bind-key -r M-l resize-pane -R

bind-key -r M-J resize-pane -D 5
bind-key -r M-K resize-pane -U 5
bind-key -r M-H resize-pane -L 5
bind-key -r M-L resize-pane -R 5

使用 Meta + j,k,h,l 来调整 pane 大小(如果使用 iTerm 的话,可能需要把 Option 键位设置成,Esc+ 键)

主食

显示当前运行程序

程序输出日志多了,不清楚当前执行的程序是什么了?

# Pane border
set-option -g pane-border-status top
# Show current cmd
if-shell "uname | grep -q Darwin" \
  "set-option -g pane-border-format ' #P: #(sleep 0.25; ps -t #{pane_tty} -o args= | tail -n 1) '"
if-shell "uname | grep -q Linux" \
  "set-option -g pane-border-format ' #P: #(sleep 0.25; ps -t #{pane_tty} -o args= --sort=etime | head -n 1) '"

我的方案是打开 panetitle ,然后把 title 设置为当前执行的程序 cmd

原理为使用 ps 命令显示当前 tty 下执行的进程,并显示 cmd

然而,这可能会打出多个进程,因为进程和它的子进程会被同时打印出来。比方说用 bash 执行了一个 shell 脚本,脚本内容如下:

sleep 3600

如果只显示父进程,那么结果是 bash foo.sh,并不能清楚知道脚本执行到哪了,我希望看到的是 sleep 3600,所以需要根据 ps 得到的结果,来获取子进程的 cmd

由于平台不一样 ps 的实现也是不一样的。经过测试,macOSlinuxps 打印出来的子进程顺序是相反的,所以两个平台要区分开来对待:Darwin 内核(也就是 macOS 的内核)的用 tail -n 1linux 内核用 head -n 1 来获取子进程的 cmd

关于命令中的 sleep 0.25 主要是因为,有时候会出现 title 失效不更新的情况,加入该命令可以极大的减少该情况的出现。

快速切换 session

同时打开的 session 有点多时,会很不方便切换。虽然 tmux 提供了 prefix key + s 来显示所有的 session 并且可以用方向键来选择切换。

但还是不够好用,我想要的是像 Context 一样的通过用 session name 来切换的功能,并且提供 fuzzy search,并在我打错字个别字时也能正常切换。

这样我只要知道 session name ,闭着眼睛也能切换 session ,不用盯着屏幕看,不用在意 session 的排序位置。

这个功能依赖 fzf 中的 fzf-tmux 程序

bind-key s run-shell "tmux list-sessions -F \"##S\" | fzf-tmux | xargs tmux switch -t; true"
bind-key S choose-tree -s

按下 prefix key + s ,你将会看到 tmux 跳出一个额外的 pane ,上面显示了所有的 session name。

tmux show session

你可以通过方向键选择,也可以直接输入 session name,回车即可跳转到该 session

tmux select session

有时候 tmux 自带的 choose-tree 也挺有用的,所以我把它的键位移到到了 prefix key + S

沙拉

tmux 滚动模式的坑

tmux 在进入 copy mode (查看 pane 历史)时,会暂停读取在 pane 中运行的 ttystdoutstderr ,如果 tty 中的程序继续往标准输出中写入,那么操作系统的 tty 缓存最终会被填满。此时程序再写入时,为避免缓冲区溢出,操作系统会会阻塞该 IO 操作。此时该程序很有可能被阻塞,假如这个程序是个提供 web 服务的 server,那么它将停止响应所有的请求。

目前 tmux 官方没有打算解决这个问题(可能是 tmux 实现原因),但有方法可以绕过这个坑。

Show history as scrollable view
bind-key F capture-pane -S -10000 -b capture\; show-buffer -b capture\; send-keys G\; delete-buffer -b capture

原理是捕获当前历史,保存到 tmux buffer 中,然后再显示 buffer 的内容。这个方案和 copy mode 的区别就是会丢失 shell 中的颜色。(tmux show-buffer 命令不支持显示颜色)

保存历史到文件

tmux 中的历史不能像普通的 shell 一样,可以通过滚动终端类软件的自带的历史记录来截取日志,假如要截取的日志很长一段,没法直接在一个页面中打印出来怎么办?

bind-key P command-prompt -p 'save history to filename:' -I '~/tmux.history' 'capture-pane -S -10000 -b capture ; save-buffer -b capture %1 ; delete-buffer -b capture'

按下 prefix key + P 即可把历史记录保存到文件中,然后想怎么分析就怎么分析 xD 。

甜点

继承当前目录

打开一个新的 panewindow ,当前目录不会继承自上一个 pane ,每次都会在用户目录,挺不方便的。

# -- Split with current direcotry --
# Split panes horizontal
bind-key '%' split-window -h -c '#{pane_current_path}'  
# Split panes vertically
bind-key '"' split-window -v -c '#{pane_current_path}'
# Create new window
bind-key c new-window -c '#{pane_current_path}'

插件管理

tpmtmux 中的插件管理器,可以用来安装管理自己喜欢的 tmux 插件,非常方便。

安装

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

推荐些我用的插件

# =---- Plugins ----=
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'XSAM/tmux-themepack'

# Continuous saving tmux environments
set -g @plugin 'tmux-plugins/tmux-resurrect'
# set -g @plugin 'tmux-plugins/tmux-continuum'
# =---- Plugins ----=

# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run -b '~/.tmux/plugins/tpm/tpm'
  • tmux-plugins/tmux-sensible:帮你配置了一些常规的设置
  • XSAM/tmux-themepack: 我改的主题(自认为还挺好看的 xD)
  • tmux-plugins/tmux-resurrect: 能保存 tmuxsession 结构,这样关机重启之后,能马上恢复

咖啡、茶

我维护了一个叫 kind-lazy 的项目,提供一些程序的快速安装脚本,其中也有本文提到的 tmux 配置。

快速安装 tmux

git clone https://github.com/XSAM/kinda-lazy.git
cd kinda-lazy/tmux
bash lazy_install.sh

喜欢的话可以给项目点个 Star 😆

Enjoy!

Ref