Tmux奇技淫巧
在日常的开发工作中,终端是我们最常用的工具之一。在终端中我们可以调用各种解释器,来执行命令,完成我们的工作。然而,对于只使用终端的默认功能的开发者来说,他们可能会错过一些强大的工具和技巧,这些工具和技巧可以大大提高工作效率。
其中一个非常有用的终端工具就是Tmux
。Tmux
是一个终端复用器,它允许我们在一个终端窗口中同时运行多个终端会话,并提供了许多有用的功能,如会话管理、窗口分割、窗格布局等。本文将介绍Tmux
的基本概念和一些常用的功能,帮助读者更好地利用Tmux
提升终端工作效率。
你当然可以使用oh-my-tmux,但是学习基础知识能够帮助你更好的使用这些工具。
1. Why Tmux?
1.1 终端复用
想象这样一个场景,我们通过ssh
连接到了远程服务器之后,默认我们会连接到一个交互式解释器中(例如bash
、zsh
)。在同一个交互式解释器中,每次只能运行一条命令,而后等到命令运行结束之后我们才能再运行下一条命令。但很多时候,我们希望能连接到多个解释器,并行执行多个命令。
例如,假设你是一名软件开发者,正在进行一个大型项目的开发工作。为了方便开发,我们需要同时进行多个任务,如运行应用程序、查看日志、执行命令等。
- 首先,你创建了一个窗口,并将其命名为"代码编辑"。在这个窗口中,你打开了代码编辑器,并开始编写项目的代码。这个窗口用于代码编辑,而为了查看终端的输出,我们还需要创建另外一个窗口
- 接下来,你创建了另一个窗口,并将其命名为"测试"。在这个窗口中,我们运行测试脚本和查看测试结果。
- 同时,你还创建了一个名为"服务器"的窗口,用于连接到远程服务器并执行一些部署和管理任务。
在这个场景下,为了完成我们的开发工作,我们打开了多个不同的窗口,而每次切换窗口时都手都需要离开键盘,去点击鼠标。这样一来我们的效率就会被极大地降低。
想象现在有一个软件:
- 我们可以通过它创建了一个和解释器的会话。在这个会话中,你可以同时进行多个任务,如运行应用程序、查看日志、执行命令等。
- 其次利用它我们能创建一个窗口,并将其命名为"代码编辑"。在这个窗口中,你打开了代码编辑器,并开始编写项目的代码。而后利用它,我们能将窗口水平分割成两个窗格,一个用于编辑代码,另一个用于查看终端输出。
- 接下来,你创建了另一个窗口,并将其命名为"测试"。在这个窗口中,你打开了一个终端,用于运行测试脚本和查看测试结果。你可以通过它提供的快捷键在不同的窗口之间快速切换,方便地在编写代码和运行测试之间进行切换。
- 最后,你还创建了一个名为"服务器"的窗口,用于连接到远程服务器并执行一些部署和管理任务。你可以在这个窗口中使用它提供窗格布局功能,将窗口垂直分割成两个窗格,一个用于连接到服务器,另一个用于执行命令和查看日志。
通过使用这个软件,你可以在同一个终端窗口中同时进行代码编辑、测试和服务器管理等多个任务,而无需打开多个终端窗口。你可以通过它的快捷键快速切换窗口和窗格,轻松地在不同任务之间切换,提高工作效率。
1.2 持久性会话
另外一个场景是,假设你正在远程连接到一台服务器,并需要在该服务器上运行一个需要较长时间才能完成的任务,比如数据处理、模型训练或后台服务。
- 那么我们连接到服务器并启动任务后,并希望在断开
SSH
连接后继续运行。这意味着即使你的SSH
会话中断或你关闭了终端窗口,任务仍会在后台继续运行。这对于长时间运行的任务非常有用,因为你不必担心任务被中断或终止。 - 但是
SSH
默认连接的终端在我们关闭SSH
连接后就会终止运行,相应的我们还在运行的任务也会被终止。
因此,在这个场景下,我们希望可以和终端进行持久性会话,这样就关闭SSH
链接或者关闭终端窗口后再次打开,你仍然可以恢复到之前的工作状态。
2. 安装Tmux
2.1 包管理器安装
在大多数Linux
发行版中,可以使用包管理器进行安装。例如,在Ubuntu
上,可以使用以下命令进行安装:
bash
sudo apt-get install tmux
2.2 手动编译安装
作为追求技术的程序员,我们当然也可以手动从源码编译安装,毕竟这样更酷。而且包管理器的软件源中的版本可能比较老,因此手动编译安装也是不错的选择。
首先下载并解压源代码
bash
mkdir ~/opt/tmux && cd ~/opt/tmux
wget -c https://github.com/tmux/tmux/releases/download/3.3a/tmux-3.3a.tar.gz
tar xzvf tmux-3.3a.tar.gz
mkdir v3.3a && mv tmux* v3.3a
然后编译
bash
cd v3.3a/tmux-3.3a
./configure --prefix=/home/jack/opt/tmux/v3.3a/
make -j $(nproc)
make install
编译完成后,就能看到已经有tmux
了
bash
cd ..
tree -L 2 -I tmux-3.3a
最后创建一个软连接,方便未来版本更新。
bash
ln -s v3.3a/bin bin
ln -s v3.3a/share share
ll
PS:别忘了添加环境变量。
bash
echo 'export PATH="/home/jack/opt/tmux/bin:${PATH}"' >> ~/.zshrc
3. Tmux基础概念
开始之前,我们先了解下Tmux
的基本概念:
Tmux
采用C/S
模型构建,输入Tmux
命令就相当于链接到了Tmux
服务器,此时默认将新建一个会话,然后会话中默认新建一个窗口,窗口中默认新建一个面板- 当前的会话会被保存在
Tmux
服务器中,即便我们退出了这个会话,下次还可以重新连接到这个回话中,其中运行的命令不会被中断
Tmux
的会话、窗口、面板之间的联系如下:
- 一个
Tmux
session
(会话)可以包含多个window
(窗口),窗口默认充满会话界面,因此这些窗口中可以运行相关性不大的任务。 - 一个
window
又可以包含多个pane
(面板),窗口下的面板,都处于同一界面下,这些面板适合运行相关性高的任务,以便同时观察到它们的运行情况。
4. Tmux的基础使用
4.1 会话操作
新建会话
新建一个tmux session非常简单,语法为tmux new -s session-name
,也可以简写为tmux
,为了方便管理,建议指定会话名称,如下。
bash
tmux # 新建一个无名称的会话
tmux new -s demo # 新建一个名称为demo的会话
注意,
Tmux
默认是不允许session之间嵌套的,因此这个命令需要在session外使用
进入会话后,终端的下面就会显示绿色的状态栏,其中描述了诸多信息。
断开当前会话
会话中操作了一段时间,我希望断开会话同时下次还能接着用,怎么做?此时可以使用detach命令。
bash
tmux detach # 断开当前会话,会话在后台运行
也许你觉得这个太麻烦了,是的,tmux的会话中,我们可以使用tmux快捷键了。使用快捷键组合Ctrl+b
+ d
,三次按键就可以断开当前会话。
进入之前的会话
断开会话后,想要接着上次留下的现场继续工作,就要使用到tmux的attach命令了,语法为tmux attach-session -t session-name
,可简写为tmux a -t session-name
或 tmux a
。通常我们使用如下两种方式之一即可:
bash
tmux a # 默认进入第一个会话
tmux a -t demo # 进入到名称为demo的会话
关闭会话
会话的使命完成后,一定是要关闭的。我们可以使用tmux的kill命令,kill命令有kill-pane
、kill-server
、kill-session
和 kill-window
共四种,其中kill-session
的语法为tmux kill-session -t session-name
。如下:
bash
tmux kill-session -t demo # 关闭demo会话
tmux kill-server # 关闭服务器,所有的会话都将关闭
查看所有的会话
管理会话的第一步就是要查看所有的会话,我们可以使用如下命令:
bash
tmux list-session # 查看所有会话
tmux ls # 查看所有会话,提倡使用简写形式
如果刚好处于会话中怎么办?别担心,我们可以使用对应的tmux快捷键Ctrl+b
+ s
,此时tmux将打开一个会话列表,按上下键(⬆︎⬇︎)或者鼠标滚轮,可选中目标会话,按左右键可收起或展开会话的窗口,选中目标会话或窗口后,按回车键即可完成切换。
重命名会话
tmux rename-session
命令用于重命名会话。
bash
tmux rename-session -t 0 <new-name>
上面命令将0号会话重命名。
但事实上一般更常用的是重命名当前会话,所以直接使用快捷键Ctrl+b
+ $
4.2 窗口操作
新建窗口
tmux new-window
命令用来创建新窗口。
bash
tmux new-window
# 新建一个指定名称的窗口
tmux new-window -n <window-name>
切换窗口
tmux select-window
命令用来切换窗口。
bash
# 切换到指定编号的窗口
tmux select-window -t <window-number>
# 切换到指定名称的窗口
tmux select-window -t <window-name>
重命名窗口
tmux rename-window
命令用于为当前窗口起名(或重命名)。
bash
tmux rename-window <new-name>
窗口快捷键
下面是一些窗口操作的快捷键。
Ctrl+b c
:创建一个新窗口,状态栏会显示多个窗口的信息。Ctrl+b p
:切换到上一个窗口(按照状态栏上的顺序)。Ctrl+b n
:切换到下一个窗口。Ctrl+b <number>
:切换到指定编号的窗口,其中的<number>
是状态栏上的窗口编号。Ctrl+b w
:从列表中选择窗口。Ctrl+b ,
:窗口重命名。
更多的命令就不介绍了,因为相比于使用命令来说,更常用的是直接使用快捷键。
5. Tmux快捷键
关于快捷键,首先要认识到的是:tmux
的所有快捷键,都包含同一个前缀,默认为Ctrl+b
,输入完前缀过后,控制台激活,命令按键才能生效。前面tmux
会话相关的操作中,我们共用到了两个快捷键Ctrl+b
+ d
、Ctrl+b
+ s
,但这仅仅是冰山一角,欲窥tmux
庞大的快捷键体系,请看下表。
5.1 Tmux系统指令
前缀 | 指令 | 描述 |
---|---|---|
Ctrl+b |
? |
显示快捷键帮助文档 |
Ctrl+b |
d |
断开当前会话 |
Ctrl+b |
D |
选择要断开的会话 |
Ctrl+b |
Ctrl+z |
挂起当前会话 |
Ctrl+b |
r |
强制重载当前会话 |
Ctrl+b |
s |
显示会话列表用于选择并切换 |
Ctrl+b |
: |
进入命令行模式,此时可直接输入ls 等命令 |
Ctrl+b |
[ |
进入复制模式,按q 退出 |
Ctrl+b |
] |
粘贴复制模式中复制的文本 |
Ctrl+b |
~ |
列出提示信息缓存 |
5.2 窗口(window)指令。
前缀 | 指令 | 描述 |
---|---|---|
Ctrl+b |
c |
新建窗口 |
Ctrl+b |
& |
关闭当前窗口(关闭前需输入y or n 确认) |
Ctrl+b |
0~9 |
切换到指定窗口 |
Ctrl+b |
p |
切换到上一窗口 |
Ctrl+b |
n |
切换到下一窗口 |
Ctrl+b |
w |
打开窗口列表,用于且切换窗口 |
Ctrl+b |
, |
重命名当前窗口 |
Ctrl+b |
. |
修改当前窗口编号(适用于窗口重新排序) |
Ctrl+b |
f |
快速定位到窗口(输入关键字匹配窗口名称) |
5.3 面板(pane)指令。
前缀 | 指令 | 描述 |
---|---|---|
Ctrl+b |
" |
当前面板上下一分为二,下侧新建面板 |
Ctrl+b |
% |
当前面板左右一分为二,右侧新建面板 |
Ctrl+b |
x |
关闭当前面板(关闭前需输入y or n 确认) |
Ctrl+b |
z |
最大化当前面板,再重复一次按键后恢复正常(v1.8版本新增) |
Ctrl+b |
! |
将当前面板移动到新的窗口打开(原窗口中存在两个及以上面板有效) |
Ctrl+b |
; |
切换到最后一次使用的面板 |
Ctrl+b |
q |
显示面板编号,在编号消失前输入对应的数字可切换到相应的面板 |
Ctrl+b |
{ |
向前置换当前面板 |
Ctrl+b |
} |
向后置换当前面板 |
Ctrl+b |
Ctrl+o |
顺时针旋转当前窗口中的所有面板 |
Ctrl+b |
方向键 |
移动光标切换面板 |
Ctrl+b |
o |
选择下一面板 |
Ctrl+b |
空格键 |
在自带的面板布局中循环切换 |
Ctrl+b |
Alt+方向键 |
以5个单元格为单位调整当前面板边缘 |
Ctrl+b |
Ctrl+方向键 |
以1个单元格为单位调整当前面板边缘(Mac下被系统快捷键覆盖) |
Ctrl+b |
t |
显示时钟 |
tmux
的丝滑分屏功能正是得益于以上系统、窗口、面板的快捷指令,只要你愿意,你就可以解除任意的快捷指令,然后绑上你喜欢的指令,当然这就涉及到tmux
的配置了。
6. Tmux的配置文件
类似于.bashrc
和.zshrc
,tmux提供了类似的配置文件。通过编写配置文件就可以实现更加强大的功能。
tmux的用户级配置文件为~/.tmux.conf
(没有的话就创建一个),修改快捷指令,只需要增加如下三行即可。如果你的主目录下还没有 .tmux.conf
文件,你可以使用文本编辑器创建一个新的文件并将其保存为 .tmux.conf
。
配置文件使用简单的语法来定义设置和命令。每个设置或命令占据一行,可以使用 #
符号进行注释。
6.0 Tmux配置文件的指令
在 Tmux 配置文件中,可以使用以下几类命令:
-
set
命令:用于设置各种选项和参数。可以使用set -g
命令设置全局选项,使用set -u
命令取消选项设置,使用set -g option value
命令设置具体的选项和对应的值。例如,set -g prefix C-a
将前缀键设置为Ctrl+a
。 -
bind-key
命令:用于创建键绑定,将特定的键映射到指定的命令。可以使用bind-key -n
命令创建无前缀键绑定,使用bind-key
命令创建带前缀键绑定。例如,bind-key -n C-a new-window
将Ctrl+a
绑定到新建窗口的命令。 -
unbind-key
命令:用于解除键绑定,取消特定键的映射。可以使用unbind-key -n
命令解除无前缀键绑定,使用unbind-key
命令解除带前缀键绑定。例如,unbind-key -n C-a
将取消Ctrl+a
的绑定。 -
source-file
命令:用于重新加载配置文件,使新的设置生效。可以使用source-file ~/.tmux.conf
命令重新加载主配置文件。这在你编辑完配置文件后需要使更改生效时非常有用。 -
alias
命令:用于创建命令别名。可以使用alias -g
命令创建全局别名,使用alias
命令创建局部别名。例如,alias -g L "list-sessions"
将L
定义为list-sessions
命令的别名。
这些命令可以在 Tmux 配置文件中使用,用于自定义和配置 Tmux 的行为、键绑定、外观和其他选项。通过合理使用这些命令,你可以根据自己的需求创建一个适合自己的 Tmux 环境。
下面就介绍一些常用的配置。
6.1 修改指令前缀
相信只要你用过几次tmux,就会发现Ctrl+b
指令前缀,着实不太方便。这两个键相距太远,按键成本太高了。因此我们首先需要将它更换为距离更近的Ctrl+a
组合键,或者不常用的 ` 键。
ini
set -g prefix C-a # 将快捷键前缀设置为Ctrl+a
unbind C-b # C-b即Ctrl+b键,unbind意味着解除绑定
bind C-a send-prefix # 绑定Ctrl+a为新的指令前缀
# 从tmux v1.6版起,支持设置第二个指令前缀
set-option -g prefix2 ` # 设置一个不常用的`键作为指令前缀,按键更快些
修改的~/.tmux.conf
配置文件有如下两种方式可以令其生效:
- restart tmux。
- 在tmux窗口中,先按下
Ctrl+b
指令前缀,然后按下系统指令:
,进入到命令模式后输入source-file ~/.tmux.conf
,回车后生效。
6.2 加载配置文件快捷键
既然快捷键如此方便,更为优雅的做法是新增一个加载配置文件的快捷键 ,这样就可以随时随地load新的配置了,如下所示。
bash
# 绑定快捷键为r
bind r source-file ~/.tmux.conf \; display-message "Config reloaded.."
请特别注意,在已经创建的窗口中,即使加载了新的配置,旧的配置依然有效(只要你新加的功能没有覆盖旧的配置,因此如果你第一次绑定快捷指令为x
键,然后又改为绑定y
键,那么x
和y
都将有效),新建会话不受此影响,将直接采用新的配置。
既然我们已经迈出配置化的第一步,那么接下来我们可以做得更多。
6.3 新增面板
tmux中,使用最多的功能之一就是新增一个面板。水平方向新增面板的指令是 prefix
+ "
,垂直方向是 prefix
+ %
,"
和 %
需要两个键同时按下才能完成,加上指令前缀至少需要3~4次按键才能组成一个完整的指令,同时这个两个键也不够醒目和方便,因此我们可以绑定两个更常用的指令 -
、|
,如下所示:
bash
unbind '"'
bind - splitw -v -c '#{pane_current_path}' # 垂直方向新增面板,默认进入当前目录
unbind %
bind | splitw -h -c '#{pane_current_path}' # 水平方向新增面板,默认进入当前目录
6.4 开启鼠标支持
默认情况下,tmux的多窗口之间的切换以及面板大小调整,需要输入指令才能完成,这一过程,涉及到的指令较多,而且操作麻烦,特别是面板大小调整,指令难以一步到位,这个时候开启鼠标支持就完美了。
对于tmux v2.1(2015.10.28)之前的版本,需加入如下配置:
bash
setw -g mode-mouse on # 支持鼠标选取文本等
setw -g mouse-resize-pane on # 支持鼠标拖动调整面板的大小(通过拖动面板间的分割线)
setw -g mouse-select-pane on # 支持鼠标选中并切换面板
setw -g mouse-select-window on # 支持鼠标选中并切换窗口(通过点击状态栏窗口名称)
有的地方可能会出现set-window-option
的写法,setw
就是它的别名。
对于tmux v2.1及以上的版本,仅需加入如下配置:
bash
set-option -g mouse on # 等同于以上4个指令的效果
需要注意的是,开启鼠标支持后,iTem2默认的鼠标选中即复制功能需要同时按下 Alt
键,才会生效。
6.5 快速面板切换
鼠标支持确实能带来很大的便捷性,特别是对于习惯了鼠标操作的tmux新手,但对于键盘爱好者而言,这不是什么好消息,对他们而言,双手不离键盘是基本素质。
虽然指令前缀加方向键
可以切换面板,但方向键
太远,不够快,不够Geek。没关系,我们可以将面板切换升级为熟悉的h
、j
、k
、l
键位。
bash
# 绑定hjkl键为面板切换的上下左右键
bind -r k select-pane -U # 绑定k为↑
bind -r j select-pane -D # 绑定j为↓
bind -r h select-pane -L # 绑定h为←
bind -r l select-pane -R # 绑定l为→
-r
表示可重复按键,大概500ms之内,重复的h
、j
、k
、l
按键都将有效,完美支持了快速切换的Geek需求。
除了上下左右外, 还有几个快捷指令可以设置。
bash
bind -r e lastp # 选择最后一个面板
bind -r ^e last # 选择最后一个窗口
bind -r ^u swapp -U # 与前一个面板交换位置
bind -r ^d swapp -D # 与后一个面板交换位置
6.6 面板大小调整
习惯了全键盘操作后,命令的便捷性不言而喻。既然面板切换的指令都可以升级,面板大小调整的指令自然也不能落后。如下配置就可以升级你的操作:
bash
# 绑定Ctrl+hjkl键为面板上下左右调整边缘的快捷指令
bind -r ^k resizep -U 10 # 绑定Ctrl+k为往↑调整面板边缘10个单元格
bind -r ^j resizep -D 10 # 绑定Ctrl+j为往↓调整面板边缘10个单元格
bind -r ^h resizep -L 10 # 绑定Ctrl+h为往←调整面板边缘10个单元格
bind -r ^l resizep -R 10 # 绑定Ctrl+l为往→调整面板边缘10个单元格
以上,resizep
即resize-pane
的别名。
6.7 面板最大化
当窗口中面板的数量逐渐增多时,每个面板的空间就会逐渐减少。为了保证有足够的空间显示内容,tmux从v1.8版本起,提供了面板的最大化功能,输入tmux-prefix+z
,就可以最大化当前面板至窗口大小,只要再重复输入一次,便恢复正常。
6.8 窗口变为面板
面板可以轻松地最大化为一个新的窗口。那么反过来,窗口是不是可以最小化为一个面板呢?
试想这样一个场景:当你打开多个窗口后,然后想将其中几个窗口合并到当前窗口中,以便对比观察输出。
实际上,你的要求就是将其它窗口变成面板,然后合并到当前窗口中。对于这种操作,我们可以在当前窗口,按下prefix
+ :
,打开命令行,然后输入如下命令:
bash
join-pane -s window01 # 合并名称为window01的窗口的默认(第一个)面板到当前窗口中
join-pane -s window01.1 # .1显式指定了第一个面板,.2就是第二个面板(我本地将面板编号起始值设置为1,默认是0)
每次执行join-pane
命令都会合并一个面板,并且指定的窗口会减少一个面板,直到面板数量为0,窗口关闭。
除了在当前会话中操作外,join-pane
命令甚至可以从其它指定会话中合并面板,格式为join-pane -s [session_name]:[window].[pane]
,如join-pane -s 2:1.1
即合并第二个会话的第一个窗口的第一个面板到当前窗口,当目标会话的窗口和面板数量为0时,会话便会关闭。
注:上一节中的swap-pane
命令与join-pane
语法基本一致。
6.9 其他配置
bash
bind m command-prompt "splitw -h 'exec man %%'" # 绑定m键为在新的panel打开man
# 绑定P键为开启日志功能,如下,面板的输出日志将存储到桌面
bind P pipe-pane -o "cat >>~/Desktop/#W.log" \; display "Toggled logging to ~/Desktop/#W.log"
6.10 恢复用户空间
tmux会话中,Mac的部分命令如 osascript
、open
、pbcopy
或 pbpaste
等可能会失效(失效命令未列全)。
部分bug列表如下:
- applescript - Unable to run 'display notification' using osascript in a tmux session
- osx - "open" command doesn't work properly inside tmux
- clipboard - Can't paste into MacVim
对此,我们可以通过安装reattach-to-user-namespace
包装程序来解决这个问题。
bash
brew install reattach-to-user-namespace
在~/.tmux.conf
中添加配置:
bash
set -g default-command "reattach-to-user-namespace -l $SHELL"
这样你的交互式shell最终能够重新连接到用户级的命名空间。由于连接状态能够被子进程继承,故以上配置保证了所有从 shell 启动的命令能够被正确地连接。
有些时候,我们可能会在不同的操作系统中共享配置文件,如果你的tmux版本大于1.9,我们还可以使用if-shell
来判断是否Mac系统,然后再指定default-command
。
bash
if-shell 'test "$(uname -s)" = Darwin' 'set-option -g default-command "exec reattach-to-user-namespace -l $SHELL"'
对于tmux v1.8及更早的版本,可以使用如下包装后的配置:
bash
set-option -g default-command 'command -v reattach-to-user-namespace >/dev/null && exec reattach-to-user-namespace -l "$SHELL" || exec "$SHELL"'
以上,$SHELL
对应于你的默认Shell,通常是/usr/bin/bash
或 /usr/local/bin/zsh
。
7. 复制模式
tmux中操作文本,自然离不开复制模式,通常使用复制模式的步骤如下:
- 输入 ``+[` 进入复制模式
- 按下
空格键
开始复制,移动光标选择复制区域 - 按下
回车键
复制选中文本并退出复制模式 - 按下 ``+]` 粘贴文本
查看复制模式默认的快捷键风格:
bash
tmux show-window-options -g mode-keys # mode-keys emacs
默认情况下,快捷键为emacs
风格。
为了让复制模式更加方便,我们可以将快捷键设置为熟悉的vi
风格,如下:
bash
setw -g mode-keys vi # 开启vi风格后,支持vi的C-d、C-u、hjkl等快捷键
7.1 自定义复制和选择快捷键
除了快捷键外,复制模式的启用、选择、复制、粘贴等按键也可以向vi
风格靠拢。
bash
bind Escape copy-mode # 绑定esc键为进入复制模式
bind -t vi-copy v begin-selection # 绑定v键为开始选择文本
bind -t vi-copy y copy-selection # 绑定y键为复制选中文本
bind p pasteb # 绑定p键为粘贴文本(p键默认用于进入上一个窗口,不建议覆盖)
以上,绑定 v
、y
两键的设置只在tmux v2.4版本以下才有效,对于v2.4及以上的版本,绑定快捷键需要使用 -T
选项,发送指令需要使用 -X
选项,请参考如下设置:
bash
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
7.2 Buffer缓存
tmux复制操作的内容默认会存进buffer
里,buffer
是一个粘贴缓存区,新的缓存总是位于栈顶,它的操作命令如下:
bash
tmux list-buffers # 展示所有的 buffers
tmux show-buffer [-b buffer-name] # 显示指定的 buffer 内容
tmux choose-buffer # 进入 buffer 选择页面(支持jk上下移动选择,回车选中并粘贴 buffer 内容到面板上)
tmux set-buffer # 设置buffer内容
tmux load-buffer [-b buffer-name] file-path # 从文件中加载文本到buffer缓存
tmux save-buffer [-a] [-b buffer-name] path # 保存tmux的buffer缓存到本地
tmux paste-buffer # 粘贴buffer内容到会话中
tmux delete-buffer [-b buffer-name] # 删除指定名称的buffer
以上buffer操作在不指定buffer-name时,默认处理是栈顶的buffer缓存。
在tmux会话的命令行输入时,可以省略上述tmux前缀,其中list-buffers的操作如下所示:
choose-buffer的操作如下所示:
默认情况下,buffers内容是独立于系统粘贴板的,它存在于tmux进程中,且可以在会话间共享。
7.3 使用系统粘贴板
存在于tmux进程中的buffer缓存,虽然可以在会话间共享,但不能直接与系统粘贴板共享,不免有些遗憾。幸运的是,现在我们有成熟的方案来实现这个功能。
A. 在Linux上使用粘贴板
通常,Linux中可以使用xclip
工具来接入系统粘贴板。
首先,需要安装xclip
。
bash
sudo apt-get install xclip
然后,.tmux.conf
的配置如下。
bash
# buffer缓存复制到Linux系统粘贴板
bind C-c run " tmux save-buffer - | xclip -i -sel clipboard"
# Linux系统粘贴板内容复制到会话
bind C-v run " tmux set-buffer \"$(xclip -o -sel clipboard)\"; tmux paste-buffer"
按下prefix
+ Ctrl
+ c
键,buffer缓存的内容将通过xlip
程序复制到粘贴板,按下prefix
+ Ctrl
+ v
键,tmux将通过xclip
访问粘贴板,然后由set-buffer命令设置给buffer缓存,最后由paste-buffer粘贴到tmux会话中。
B. 在Mac上使用粘贴板
我们都知道,Mac自带 pbcopy
和 pbpaste
命令,分别用于复制和粘贴,但在tmux命令中它们却不能正常运行。这里我将详细介绍下原因:
Mac的粘贴板服务是在引导命名空间注册的。命名空间存在层次之分,更高级别的命名空间拥有访问低级别命名空间(如root引导命名空间)的权限,反之却不行。流程创建的属于Mac登录会话的一部分,它会被自动包含在用户级的引导命名空间中,因此只有用户级的命名空间才能访问粘贴板服务。tmux使用守护进程(3)库函数创建其服务器进程,在Mac OS X 10.5中,苹果改变了守护进程(3)的策略,将生成的过程从最初的引导命名空间移到了根引导命名空间。而根引导命名空间访问权限较低,这意味着tmux服务器,和它的子进程,一同失去了原引导命名空间的访问权限(即无权限访问粘贴板服务)。
如此,我们可以使用一个小小的包装程序来重新连接到合适的命名空间,然后执行访问用户级命名空间的粘贴板服务,这个包装程序就是reattach-to-user-namespace
。
那么,Mac下.tmux.conf
的配置如下:
bash
# buffer缓存复制到Mac系统粘贴板
bind C-c run "tmux save-buffer - | reattach-to-user-namespace pbcopy"
# Mac系统粘贴板内容复制到会话
bind C-v run "reattach-to-user-namespace pbpaste | tmux load-buffer - \; paste-buffer -d"
reattach-to-user-namespace
作为包装程序来访问Mac粘贴板,按下prefix
+ Ctrl
+ c
键,buffer缓存的内容将复制到粘贴板,按下prefix
+ Ctrl
+ v
键,粘贴板的内容将通过 load-buffer 加载,然后由 paste-buffer 粘贴到tmux会话中。
为了在复制模式中使用Mac系统的粘贴板,可做如下配置:
bash
# 绑定y键为复制选中文本到Mac系统粘贴板
bind-key -T copy-mode-vi 'y' send-keys -X copy-pipe-and-cancel 'reattach-to-user-namespace pbcopy'
# 鼠标拖动选中文本,并复制到Mac系统粘贴板
bind-key -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel "pbcopy"
完成以上配置后记得重启tmux服务器。至此,复制模式中,按y
键将保存选中的文本到Mac系统粘贴板,随后按Command
+ v
键便可粘贴。