linux命令tumx
命令行的典型使用方式是,打开一个终端窗口(terminal window,以下简称"窗口"),在里面输入命令。用户与计算机的这种临时的交互,称为一次"会话"(session) 。
会话的一个重要特点是,窗口与其中启动的进程是连在一起的。打开窗口,会话开始;关闭窗口,会话结束,会话内部的进程也会随之终止,不管有没有运行完。
一个典型的例子就是,SSH 登录远程计算机,打开一个远程窗口执行命令。这时,网络突然断线,再次登录的时候,是找不回上一次执行的命令的。因为上一次 SSH 会话已经终止了,里面的进程也随之消失了。
为了解决这个问题,会话与窗口可以"解绑":窗口关闭时,会话并不终止,而是继续运行,等到以后需要的时候,再让会话"绑定"其他窗口。
tldr
1 | Start a new session: |
usage
tumx: Terminal multiplexer. It allows multiple sessions with windows, panes, and more.
Tmux 就是会话与窗口的"解绑"工具,通过C-S架构将它们彻底分离。

类似的终端复用器还有 GNU Screen。Tmux 与它功能相似,但是更易用,也更强大。
安装
1 | Ubuntu 或 Debian |
使用tmux

如图所示上面就是tmux的日常使用界面。
最下面是状态栏 ,状态栏左侧 [test] 0:zsh* 1:vim~
中test 是指session name,0是指session下的第一个window。zsh*
是窗口名。状态栏右侧是当前机器信息。
Tmux 窗口有大量的快捷键。所有快捷键都要通过前缀键唤起。默认的前缀键是Ctrl+b,即先按下Ctrl+b,快捷键才会生效。举例来说,帮助命令的快捷键是Ctrl+b ?。它的用法是,在 Tmux 窗口中,先按下Ctrl+b,再按下?,就会显示帮助信息。
会话
1 | 新建会话 |
除了会话命令,tmux在还支持一些会话快捷键。
1 | Ctrl+b d:分离当前会话。 |
窗口
tmux的session会默认有一个窗口。也就是窗口0。此外Tmux 也允许新建多个窗口。
1 | 新建窗口 |
下面是一些窗口操作的快捷键。
1 | Ctrl+b c #创建一个新窗口,状态栏会显示多个窗口的信息。 |
窗格
Tmux 可以将窗口分成多个窗格(pane),每个窗格运行不同的命令。以下命令都是在 Tmux 窗口中执行。
1 | 划分上下两个窗格 |
下面是一些窗格的快捷键
1 | `Ctrl+b %`:划分左右两个窗格。 |
窗格同步操作
tmux 支持在窗口中的多个窗格同时输入,输入 Tmux 前缀(Ctrl+b)和一个冒号呼出命令提示行,然后输入setw synchronize-panes
1 | Ctrl+b : setw synchronize-panes |
可以指定同步窗格开或关,重复执行命令会在两者间切换。这个选项值针对某个窗口有效,不会影响别的会话和窗口。
全部pane同步
在 .tmux.conf
中加上如下绑定键:
1 | bind E command-prompt -p "Command:" \ |
- 在任何窗格中键入
Ctrl+b E
- 输入要发送到所有窗格的命令,回车结束
调整窗格尺寸
如果不喜欢默认布局,可以重调窗格的尺寸。这几个命令用来调整窗格(通过命令提示行方式修改):
1 | Ctrl+b : resize-pane -D 当前窗格向下扩大 1 格 |
其他命令
1 | 列出所有快捷键,及其对应的 Tmux 命令 |
tumx 配置
相信只要你用过几次tmux,就会发现Ctrl+b指令前缀,着实不太方便。这两个键相距太远,按键成本太高了。因此我们首先需要将它更换为距离更近的Ctrl+a组合键,或者不常用的 ` 键(当然其他键也是可以的)。tmux的用户级配置文件为~/.tmux.conf(没有的话就创建一个)。
修改指令前缀
修改tmux指令前缀,只需要增加如下三行即可。
1 | set -g prefix C-a # |
reload 配置
修改的~/.tmux.conf配置文件有如下两种方式可以令其生效:
1 | 1. restart tmux。 |
更为优雅的做法是新增一个加载配置文件的快捷指令 ,这样就可以随时随地load新的配置了,如下所示。
1 | 绑定快捷键为r |
新增面板
tmux中,使用最多的功能之一就是新增一个面板。水平方向新增面板的指令是 Ctrl+b "
,垂直方向是 Ctrl+b %
," 和 %需要两个键同时按下才能完成,加上指令前缀至少需要3~4次按键才能组成一个完整的指令,同时这个两个键也不够醒目和方便,因此我们可以绑定两个更常用的指令 -、|,如下所示:
1 | unbind '"' |
鼠标支持
默认情况下,tmux的多窗口之间的切换以及面板大小调整,需要输入指令才能完成,这一过程,涉及到的指令较多,而且操作麻烦,特别是面板大小调整,指令难以一步到位,这个时候开启鼠标支持就完美了。
对于tmux v2.1(2015.10.28)之前的版本,需加入如下配置:
1 | setw -g mode-mouse on # 支持鼠标选取文本等 |
有的地方可能会出现set-window-option的写法,setw就是它的别名。
对于tmux v2.1及以上的版本,仅需加入如下配置:
1 | set-option -g mouse on # 等同于以上4个指令的效果 |
需要注意的是,开启鼠标支持后,iTem2默认的鼠标选中即复制功能需要同时按下 Alt 键,才会生效。
快速面板切换
指令前缀加方向键可以切换面板,但方向键太远,不够快,不够Geek。没关系,我们可以将面板切换升级为熟悉的h、j、k、l键位。
1 | 绑定hjkl键为面板切换的上下左右键 |
-r表示可重复按键,大概500ms之内,重复的h、j、k、l按键都将有效,完美支持了快速切换的Geek需求。
除了上下左右外, 还有几个快捷指令可以设置。
1 | bind -r e lastp # 选择最后一个面板 |
面板大小调整
习惯了全键盘操作后,命令的便捷性不言而喻。既然面板切换的指令都可以升级,面板大小调整的指令自然也不能落后。如下配置就可以升级你的操作:
1 | 绑定Ctrl+hjkl键为面板上下左右调整边缘的快捷指令 |
面板最大化
当窗口中面板的数量逐渐增多时,每个面板的空间就会逐渐减少。为了保证有足够的空间显示内容,tmux从v1.8版本起,提供了面板的最大化功能,输入Ctrl+b z
,就可以最大化当前面板至窗口大小,只要再重复输入一次,便恢复正常。那么tmux v1.8以下的版本,怎么办呢?别急,有大神提供了如下的解决方案。
首先编写一个zoom脚本,该脚本通过新建一个窗口,交换当前面板与新的窗口默认面板位置,来模拟最大的功能;通过重复一次按键,还原面板位置,并关闭新建的窗口,来模拟还原功能,如下所示:
1 | !/bin/bash -f |
不妨将该脚本存放在~/.tmux目录中(没有则新建目录),接下来只需要绑定一个快捷指令就行,如下。
1 | unbind z |
窗口变为面板
通过上面的zoom脚本,面板可以轻松地最大化为一个新的窗口。那么反过来,窗口是不是可以最小化为一个面板呢?
试想这样一个场景:当你打开多个窗口后,然后想将其中几个窗口合并到当前窗口中,以便对比观察输出。
Ctrl+b :
,打开命令行,然后输入如下命令:
1 | join-pane -s window01 # 合并名称为window01的窗口的默认(第一个)面板到当前窗口中 |
每次执行join-pane命令都会合并一个面板,并且指定的窗口会减少一个面板,直到面板数量为0,窗口关闭。
除了在当前会话中操作外,join-pane命令甚至可以从其它指定会话中合并面板,格式为 join-pane -s [session_name]:[window].[pane]
,如join-pane -s 2:1.1
即合并第二个会话的第一个窗口的第一个面板到当前窗口,当目标会话的窗口和面板数量为0时,会话便会关闭。
注:上一节中的swap-pane命令与join-pane语法基本一致。
其他配置
1 | bind m command-prompt "splitw -h 'exec man %%'" # 绑定m键为在新的panel打开man |
恢复用户空间
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包装程序来解决这个问题。
1 | brew install reattach-to-user-namespace |
在~/.tmux.conf中添加配置:
1 | set -g default-command "reattach-to-user-namespace -l $SHELL" |
这样你的交互式shell最终能够重新连接到用户级的命名空间。由于连接状态能够被子进程继承,故以上配置保证了所有从 shell 启动的命令能够被正确地连接。
有些时候,我们可能会在不同的操作系统中共享配置文件,如果你的tmux版本大于1.9,我们还可以使用if-shell来判断是否Mac系统,然后再指定default-command。
1 | if-shell 'test "$(uname -s)" = Darwin' 'set-option -g default-command "exec reattach-to-user-namespace -l $SHELL"' |
对于tmux v1.8及更早的版本,可以使用如下包装后的配置:
1 | 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。
复制模式
tmux中操作文本,自然离不开复制模式,通常使用复制模式的步骤如下:
1 | 输入 `Ctrl+b [` 进入复制模式 |
查看复制模式默认的快捷键风格:
1 | tmux show-window-options -g mode-keys # mode-keys emacs |
默认情况下,快捷键为emacs风格。
为了让复制模式更加方便,我们可以将快捷键设置为熟悉的vi风格,如下:
1 | setw -g mode-keys vi # 开启vi风格后,支持vi的C-d、C-u、hjkl等快捷键 |
自定义复制和选择快捷键
除了快捷键外,复制模式的启用、选择、复制、粘贴等按键也可以向vi风格靠拢。
1 | bind Escape copy-mode # 绑定esc键为进入复制模式 |
以上,绑定 v、y两键的设置只在tmux v2.4版本以下才有效,对于v2.4及以上的版本,绑定快捷键需要使用 -T 选项,发送指令需要使用 -X 选项,请参考如下设置:
1 | bind -T copy-mode-vi v send-keys -X begin-selection |
Buffer缓存
tmux复制操作的内容默认会存进buffer里,buffer是一个粘贴缓存区,新的缓存总是位于栈顶,它的操作命令如下:
1 | tmux list-buffers # 展示所有的 buffers |
以上buffer操作在不指定buffer-name时,默认处理是栈顶的buffer缓存。在tmux会话的命令行输入时,可以省略上述tmux前缀。默认情况下,buffers内容是独立于系统粘贴板的,它存在于tmux进程中,且可以在会话间共享。
使用系统粘贴板
存在于tmux进程中的buffer缓存,虽然可以在会话间共享,但不能直接与系统粘贴板共享,不免有些遗憾。幸运的是,现在我们有成熟的方案来实现这个功能。
在Linux上使用粘贴板
通常,Linux中可以使用xclip工具来接入系统粘贴板。
首先,需要安装xclip。
1 | sudo apt-get install xclip |
然后,.tmux.conf的配置如下。
1 | buffer缓存复制到Linux系统粘贴板 |
按下Ctrl+b Ctrl+c
键,buffer缓存的内容将通过xlip程序复制到粘贴板,按下 Ctrl+b Ctrl+v
,tmux将通过xclip访问粘贴板,然后由set-buffer命令设置给buffer缓存,最后由paste-buffer粘贴到tmux会话中。
在Mac上使用粘贴板
我们都知道,Mac自带 pbcopy 和 pbpaste命令,分别用于复制和粘贴,但在tmux命令中它们却不能正常运行。这里我将详细介绍下原因:
Mac的粘贴板服务是在引导命名空间注册的。命名空间存在层次之分,更高级别的命名空间拥有访问低级别命名空间(如root引导命名空间)的权限,反之却不行。流程创建的属于Mac登录会话的一部分,它会被自动包含在用户级的引导命名空间中,因此只有用户级的命名空间才能访问粘贴板服务。tmux使用守护进程(3)库函数创建其服务器进程,在Mac OS X 10.5中,苹果改变了守护进程(3)的策略,将生成的过程从最初的引导命名空间移到了根引导命名空间。而根引导命名空间访问权限较低,这意味着tmux服务器,和它的子进程,一同失去了原引导命名空间的访问权限(即无权限访问粘贴板服务)。
如此,我们可以使用一个小小的包装程序来重新连接到合适的命名空间,然后执行访问用户级命名空间的粘贴板服务,这个包装程序就是reattach-to-user-namespace。
那么,Mac下.tmux.conf的配置如下:
1 | buffer缓存复制到Mac系统粘贴板 |
reattach-to-user-namespace 作为包装程序来访问Mac粘贴板,按下Ctrl+b Ctrl+c
键,buffer缓存的内容将复制到粘贴板,按下Ctrl+b Ctrl+v
键,粘贴板的内容将通过 load-buffer 加载,然后由 paste-buffer 粘贴到tmux会话中。
为了在复制模式中使用Mac系统的粘贴板,可做如下配置:
1 | 绑定y键为复制选中文本到Mac系统粘贴板 |
完成以上配置后记得重启tmux服务器。至此,复制模式中,按y键将保存选中的文本到Mac系统粘贴板,随后按Command + v键便可粘贴。
保存Tmux会话
tmux保护现场的能力依赖于tmux进程,如果进程退出,则意味着会话数据的丢失,因此关机重启后,tmux中的会话将被清空,这不是我们想要见到的。幸运的是,目前有这样两款插件:Tmux Resurrect 和 Tmux Continuum,可以永久保存tmux会话(它们均适用于tmux v1.9及以上版本)。
Tmux Resurrect
Tmux Resurrect无须任何配置,就能够备份tmux会话中的各种细节,包括窗口、面板的顺序、布局、工作目录,运行程序等等数据。因此它能在系统重启后完全地恢复会话。由于其幂等的恢复机制,它不会试图去恢复一个已经存在的窗口或者面板,所以,即使你不小心多恢复了几次会话,它也不会出现问题,这样主动恢复时我们就不必担心手抖多按了一次。另外,如果你是tmuxinator用户,我也建议你迁移到 tmux-resurrect插件上来,具体请参考Migrating from tmuxinator。
Tmux Resurrec安装过程如下所示:
1 | cd ~/.tmux |
安装后需在~/.tmux.conf中增加一行配置:
1 | run-shell ~/.tmux/plugins/tmux-resurrect/resurrect.tmux |
至此安装成功,重载tmux配置。
Tmux Resurrec提供如下两个操作:
- 保存,快捷指令是
Ctrl+b Ctrl+s
,tmux状态栏在保存开始,保存后分别提示”Saving…”,”Tmux environment saved !”。 - 恢复,快捷指令是
Ctrl+b Ctrl+r
,tmux状态栏在恢复开始,恢复后分别提示”Restoring…”,”Tmux restore complete !”。
保存时,tmux会话的详细信息会以文本文件的格式保存到~/.tmux/resurrect目录,恢复时则从此处读取,由于数据文件是明文的,因此你完全可以自由管理或者编辑这些会话状态文件(如果备份频繁,记得定期清除历史备份)。
可选的配置
Tmux Resurrec本身是免配置开箱即用的,但同时也提供了如下选项以便修改其默认设置。
1 | set -g @resurrect-save 'S' # 修改保存指令为S |
默认情况下只有一个保守的列表项(即vi vim nvim emacs man less more tail top htop irssi mutt)可以恢复,对此 Restoring programs doc 解释了怎么去恢复额外的项目。
进阶的备份
除了基础备份外,Tmux Resurrec还提供进阶的备份功能,如下所示:
- 恢复vim 和 neovim 会话
- 恢复面板内容
- 恢复shell的历史记录(实验性功能)
进阶的备份功能默认不开启,需要特别配置。
- 恢复vim 和 neovim 会话,需要完成如下两步:
通过vim的vim-obsession插件保存vim/neovim会话。
1 | cd ~/.vim/bundle |
在~/.tmux.conf中增加两行配置:
1 | set -g @resurrect-strategy-vim 'session' # for vim |
- 恢复面板内容,需在~/.tmux.conf中增加一行配置:
1 | set -g @resurrect-capture-pane-contents 'on' # 开启恢复面板内容功能 |
目前使用该功能时,请确保tmux的default-command没有包含&& 或者||操作符,否则将导致bug。(查看default-command的值,请使用命令tmux show -g default-command。)
- 恢复shell的历史记录,需在~/.tmux.conf中增加一行配置:
1 | set -g @resurrect-save-shell-history 'on' |
由于技术的限制,保存时,只有无前台任务运行的面板,它的shell历史记录才能被保存。
Tmux Continuum
可能你嫌手动保存和恢复太过麻烦,别担心,这不是问题。Tmux Continuum 在 Tmux Resurrec的基础上更进一步,现在保存和恢复全部自动化了,如你所愿,可以无感使用tmux,不用再担心备份问题。
Tmux Continuum安装过程如下所示(它依赖Tmux Resurrect,请保证已安装Tmux Resurrect插件):
1 | cd ~/.tmux/plugins |
安装后需在~/.tmux.conf中增加一行配置:
1 | run-shell ~/.tmux/plugins/tmux-continuum/continuum.tmux |
Tmux Continuum默认每隔15mins备份一次,我设置的是一天一次:
1 | set -g @continuum-save-interval '1440' |
关闭自动备份,只需设置时间间隔为 0 即可:
1 | set -g @continuum-save-interval '0' |
想要在tmux启动时就恢复最后一次保存的会话环境,需增加如下配置:
1 | set -g @continuum-restore 'on' # 启用自动恢复 |
如果不想要启动时自动恢复的功能了,直接移除上面这行就行。想要绝对确定自动恢复不会发生,就在用户根目录下创建一个tmux_no_auto_restore空文件(创建命令:touch ~/tmux_no_auto_restore),该文件存在时,自动恢复将不触发。
对于tmux高级用户(可能就是你)而言,同时运行多个tmux服务器也是有可能的。你可能并不希望后面启用的几个tmux服务器自动恢复或者自动保存会话。因此Tmux Continuum会优先在第一个启用的tmux服务器中生效,随后启用的tmux服务器不再享受自动恢复或自动保存会话的待遇。
实际上,不管Tmux Continuum功能有没有启用,或者多久保存一次,我们都有办法从状态栏知晓。Tmux Continuum提供了一个查看运行状态的插值#{continuum_status},它支持status-right 和 status-left两种状态栏设置,如下所示:
1 | set -g status-right 'Continuum status: #{continuum_status}' |
tmux运行时,#{continuum_status} 将显示保存的时间间隔(单位为分钟),此时状态栏会显示:
1 | Continuum status: 1440 |
如果其自动保存功能关闭了,那么状态栏会显示:
1 | Continuum status: off |
借助Tmux Continuum插件,Mac重启时,我们甚至可以选择在Terminal 或者 iTerm2 中自动全屏启用tmux。
为此,需在~/.tmux.conf中增加一行配置:
1 | set -g @continuum-boot 'on' |
Mac下,自动启用tmux还支持如下选项:
1 | set -g @continuum-boot-options 'fullscreen' ,Terminal自动全屏,tmux命令在Terminal中执行。 |
Linux中则没有这些选项,它只能设置为自动启用tmux服务器。
TPM
以上,我们直接安装了tmux插件。这没有问题,可当插件越来越多时,我们就会需要统一的插件管理器。因此官方提供了tpm(支持tmux v1.9及以上版本)。
tpm安装过程如下所示:
1 | cd ~/.tmux/plugins |
安装后需在~/.tmux.conf中增加如下配置:
1 | 默认需要引入的插件 |
然后重载tmux配置,使得tpm生效。
基于tpm插件管理器,安装插件仅需如下两步:
- 在~/.tmux.conf中增加新的插件,如set -g @plugin ‘…’。
- 按下
Ctrl+b I
键下载插件,并刷新tmux环境。
更新插件,请按下Ctrl+b U
键,选择待更新的插件后,回车确认并更新。
卸载插件,需如下两步:
- 在~/.tmux.conf中移除插件所在行。
- 按下
Ctrl+b alt + u
移除插件。
会话共享
tmux多会话连接实时同步的功能,使得结对编程成为了可能,这也是开发者最喜欢的功能之一。现在就差一步了,就是借助tmate把tmux会话分享出去。
tmate是tmux的管理工具,它可以轻松的创建tmux会话,并且自动生成ssh链接。
安装tmate
1 | brew install tmate |
使用tmate新建一个tmux会话
1 | tmate |
查看tmate生成的ssh链接
1 | tmate show-messages |
共享账号&组会话
使用tmate远程共享tmux会话,受制于多方的网络质量,必然会存在些许延迟。如果共享会话的多方拥有同一个远程服务器的账号,那么我们可以使用组会话解决这个问题。
先在远程服务器上新建一个公共会话,命名为groupSession。
1 | tmux new -s groupSession |
其他用户不去直接连接这个会话,而是通过创建一个新的会话来加入上面的公共会话groupSession。
1 | tmux new -t groupSession -s otherSession |
此时两个用户都可以在同一个会话里操作,就会好像第二个用户连接到了groupSession的会话一样。此时两个用户都可以创建新建的窗口,新窗口的内容依然会实时同步,但是其中一个用户切换到其它窗口,对另外一个用户没有任何影响,因此在这个共享的组会话中,用户各自的操作可以通过新建窗口来执行。即使第二个用户关闭otherSession会话,共享会话groupSession依然存在。
组会话在共享的同时,又保留了相对的独立,非常适合结对编程场景,它是结对编程最简单的方式,如果账号不能共享,我们就要使用下面的方案了。
独立账号&Socket共享会话
开始之前我们需要确保用户对远程服务器上同一个目录拥有相同的读写权限,假设这个目录为/var/tmux/。
使用new-session(简写new)创建会话时,使用的是默认的socket位置,默认socket无法操作,所以我们需要创建一个指定socket文件的会话。
1 | tmux -S /var/tmux/sharefile |
另一个用户进入时,需要指定socket文件加入会话。
1 | tmux -S /var/tmux/sharefile attach |
这样,两个不同的用户就可以共享同一个会话了。
通常情况下,不同的用户使用不同的配置文件来创建会话,但是,使用指定socket文件创建的tmux会话,会话加载的是第一个创建会话的用户的~/.tmux.conf配置文件,随后加入会话的其他用户,依然使用同一份配置文件。
Tmux优化
1 | 设置窗口面板起始序号 |
tmux默认会同步同一个会话的操作到所有会话连接的终端窗口中,这种同步机制,限制了窗口的大小为最小的会话连接。因此当你开一个大窗口去连接会话时,实际的窗口将自动调整为最小的那个会话连接的窗口,终端剩余的空间将填充排列整齐的小圆点.为了避免这种问题,我们可以在连接会话的时候,断开其他的会话连接。
1 | tmux a -d |
如果已经进入了tmux会话中,才发现这种问题,这个时候可以输入命令达到同样的效果。
1 | Ctrl+b : a -d |
脚本化的Tmux
1 | !/usr/bin/env sh |
tmux 实现平铺视图
1 | !/bin/sh |
每4次split-window后要执行一次
tmux select-layout tiled
。